Zoho Desk Platform
Introduction

ZOHO MARKETPLACE - AN INTRODUCTION

At Zoho Desk, we believe in delivering good user experiences and making already good experiences better. In that vein, stepping into Zoho Marketplace is an effort towards achieving the latter goal.

Zoho Marketplace is an online store where users can find extensions that deliver business value by enhancing the core functionality of the Zoho product they use. It is similar to Google's Play Store, where you find apps for installation and use, according to your need. Until now, one could create extensions only for Zoho CRM, Creator, Connect, Cliq, Recruit, SalesIQ, Mail, and Reports. Going forward, they can create extensions for Zoho Desk too, and make a positive impact in the customer service space.

As a developer, you can create extensions that combine Zoho Desk's functionalities with those of third-party tools to make work easier and more effective for the end-users of Zoho Desk. You do not require extensive expertise or experience in programming to create extensions. Functional knowledge of HTML, CSS, and JavaScript can help you to a great extent.

After you create and submit your extension for review, we test its functionalities and provide you with feedback for improving its effectiveness, if required. When the extension is ready for use, we host it on Marketplace for end-users to discover and use.

Quick Start

Installing the Node

$ node -v v7.1.0 or Above

As the first step to creating an extension, you must install the node.js runtime environment. You can download node.js from here (versions above 7.1.0 are supported). After installing node.js, you can verify its version using the following command:

Installing the ZET CLI

Next, you must install the ZET (Zoho Extension Toolkit) Command Line Interface (CLI) tool, which enables you to build, test, and package extensions for Zoho products.

sudo npm install -g zoho-extension-toolkit

If you use a Mac/Unix system for development, run the following command to install ZET:

npm install -g zoho-extension-toolkit

If you use a Microsoft Windows system, run the following command:

The -g command option ensures that the installation is global. With a global installation, you can call commands and work on your extensions and CLI from anywhere within your machine.

zet -v 0.17.1

After ZET is installed, help information regarding the zet command would appear. You can then verify the version of the tool, using the following command:

D: \zet\projects\demoproject>zet -help Usage: index [options] [command] Options: -v, —version Show the version number -h, —help output usage information Commands: Init, Creates a new project template directory run Starts a local server with current directory as context Validate Validates the current app with validation rules Pack Packs the project to upload into marketplace

Running ZET will display all the commands supported, as shown in the right panel.














init

zet init

This command creates a new project for the extension.

D:\zet\projects>zet init ? Select the Zoho service for your widget and hit enter key (Use arrow keys) > Zoho Desk Zoho CRM ZES

Executing this command displays the list of Zoho Services available. Choose Zoho Desk and press the Enter key.




D:\zet\projects>zet init ? Select the Zoho service for your widget and hit enter key Zoho Desk ? Project Name demoproject

After choosing Zoho Desk, provide a name for the new project.



D:\zet\projects>D:\zet\projects>zet init ? Select the Zoho service for your widget and hit enter key Zoho Desk ? Project Name demoproject Initializing project at: D:\zet\projects\demoprojects Installing NPM dependencies… Project Initialized D:\zet\projects\demoprojects Run the following commands: Cd demoproject Zet run D:\zet\projects>

After you enter the name, a project template directory with all the necessary folders, dependency node packages, and files is created.









The image below shows the default folder structure of an extension project.

run

This command runs the http server hosting the extension.

D:\zet\projects>D:\zet\projects>zet run

1. To start the server and test the extension, run the following command:

This command makes the http server accessible through the 5000 port of your local machine. Make sure that the 5000 port is not occupied, before you start the server.

2. To verify if the server started successfully, open the following URL in your browser: http://localhost:5000/plugin-manifest.json

validate

D:\zet\projects>zet validate

This command validates the extension by checking if it follows the guidelines defined in this section. To perform this validation, run the following command:

After you execute this command, the result of the validation appears. Check the result and make any changes, if required. After this step, you can proceed to package the extension files for upload.

Guidelines

During validation, the details in the plugin-manifest.json file are checked to verify if the following conditions are met:

pack

zet pack

The project directory contains the source code and other node modules necessary for locally testing the extension. However, the final zip file you upload to Marketplace must contain only the files and folders essential for running the extension. ZET makes this packaging process easy through the following command:

After you execute this command, ZET creates a zip file containing all files in the app folder and the plugin-manifest.json file of your extension. This zip file is stored in the dist folder of the project.

Building Your First Extension

Let’s get started by creating an extension. First, open the terminal/command prompt window, and navigate to the directory under which you want to create your extension.

Then, perform the following steps:

  1. Run the init command.
  2. Under the list of services, choose Zoho Desk.
  3. Enter a name for the extension project.
  4. Press the Enter key.

The extension project is created with the necessary directories and files.

Testing the Extension

To test your extension, perform the following steps:

  1. Open the terminal/command prompt and navigate to your project folder.
  2. Execute the zet run command.
  3. Log into your Zoho Desk account. If you do not have a Zoho Desk account, sign up here.
  4. While on the Zoho Desk page, open browser developer tools, and from the console, invoke the runDevMode() JavaScript code. This action refreshes the page and activates the development mode.
  5. Open a ticket and click the Marketplace icon. The extension appears.



The runDevMode() command loads Zoho Desk in developer mode. To revert to normal mode, execute the runProdMode() command in developer tools.

Validating the Extension

To validate your extension and verify if it follows the guidelines mentioned earlier, perform the following steps:

  1. Open the terminal/command prompt and navigate to your project folder.
  2. Execute the zet validate command.
    The results of the validation process appear. Make changes, if required.

Packaging the Extension

To package your extension as a zip file that contains only the relevant files, perform the following steps:

  1. Open the terminal/command prompt and navigate to your project folder.
  2. Execute the zet pack command.
    The zip file of your extension is created in the dist folder of your project.

Uploading the Extention

Uploading the Extension to the Marketplace

After packaging your extension, perform the following steps to upload the zip file of your extension for review:

  1. Go to the Zapps website.
  2. Click the Submit button.



    The upload process flow begins.

Based on the visibility option you choose, your extension can be of two types:

Private:

If you want to use the extension only within your organization or help desk portal, choose Private in the upload form. After you complete the upload process, you will be provided with an installation URL, using which you can install the extension in your portal.

Public:

If you want to let other end-users of Zoho Desk find your extension in Marketplace and install it in their portal, choose Public in the upload form. The form through which you submit more details of your extension appears. Follow the wizard through and upload your extension.

  1. In the General information form, provide the following details:
    • Release Audience: Visibility option for the extension: Public or Private
    • Developer Name/Org: Name of the organization or individual developer who created the extension
    • Contact Number: Phone number to contact the extension developer
    • Developer Website: Website of the extension developer
    • Help URL: Link to the extension's help documentation

    After entering these details, click the Next Step button. The App information form appears.

  2. In the App information form, enter the following details:
    • App Title: Name of the extension
    • Tagline: Short, catchy phrase that describes the function of the extension
    • Category: Business function/operation related to the extension
    • App Description: Brief description of the extension
    • App Summary: Development summary of the extension and other important notes
    • Logo: Logo of the extension/product/developer
    • Banner: Banner image that should appear on the extension detail page
    • Screenshots: Screenshots of the extension

    After entering these details, click the Next Step button. The Uploads form appears.

  3. In the Uploads form, configure the following settings:
    • Zoho Service: Zoho product related to the extension
    • Upload Zip File: Final, packaged zip file of the extension

    After performing these steps, click the Next Step button. The Validation page appears.

  4. On the Validation page, verify the details you entered, and perform one of these two steps::
    • If all the information is accurate, click the Save button. The extension will be submitted for review.
    • If any inaccurate information is present, click the Back button and perform the required corrections in the relevant form. After making the necessary correction(s), click the Save button in the Validation page.

    After you upload your extension on the Zapps site, the Zoho Desk team reviews it for functionality and usability, and provides you with feedback if any enhancements are required. The extension is made available on Marketplace after it passes the review and functions as intended.

Updating the Extension

Updating the Extension to the Marketplace

IIf you come up with new features, enhancements to existing features, or bug fixes, you can update your extension to improve its functionality and performance. Each update increments the version of the extension.

To upload the updated version of your extension, perform the following steps:

  1. Go to the Zapps website and click your extension.
  2. On the upper-right corner of the extension detail page, click the Edit button. The extension information form with previously filled data appears. Edit the details, if required, and click Next.
  3. In the final form, upload the zip file of the updated extension and submit it for review.

The review process of the updated extension begins.

After the review is completed, one of these two events happens:

Installing the Extension

Installing the Extension in Zoho Desk

End-users of Zoho Desk can view and install the public extensions you create, from two locations:

If the Zoho Desk administrator installs an extension from the Setup page, the extension is made available to users in the current portal. On the other hand, if the administrator tries to install the extension from the Marketplace site, a list of all the available portals appears, letting the admin choose the one in which the extension must be installed.

Configuration

Below are the different configurations you can set for your extension.

plugin-manifest

The configuration details of each extension are stored in the plugin-manifest.json file in the extension project directory. The various keys included in this file are as follows:



































{
 “location” - Location of the widget. All locations are predefined and explained in this document, “url” - starting point of the widget. Can be either a relative path (for internally hosted extentions) or an absolute path (for externally hosted extensions), “name” - Name of the extension (displayed in the extension header), “logo” - Logo of the extension (displayed in the extension header), “icon” - Icon of the extension (displayed only on widgets on the chat bar and subtab) }



















{ “name” : Name of the parameter which will be used to replace the values and displayed as a label “userdefined” : true (input value to be given by user), “type” : Input type (text field/drop-down) list/radio button); only text field is supported currently, “value” : Initial value of the parameter, “mandatory” : This property performs validation check when the user misses to enter values during installation, “secure” : true - values will be available only on the server side of the product; the client side will not have access to the values. false - values will be available on the client side0. }

{ “name” : Name of the parameter which will be used to replace the values “value” : Value of the parameter }

Configuring connectors

To configure a connector for a third-party service, perform the following steps:

  1. Visit the All Connections page on the Zapps site.
  2. Click Add Connection.
    The list of third-party services currently supported appears.
  3. Click the service you want.
    The Connection Details form appears.
  4. In this form, enter a name for the connection of your choice and choose the access scopes for the connection.
  5. Then, click the Create and Connect button.
    The Connection Summary page appears.
  6. On this page, click the JSON tab.
  7. Copy the code snippet under the JSON tab.
  8. Go to the plugin-manifest.json file of your extension and paste the code snippet under the connectors key.

Your extension is now connected to the third-party service.

To configure your extension to fetch data from the third-party service, include the connectionLinkName key in the request API.

Locations

This key, which must be configured in the plugin-manifest file, defines the location(s) for your extension's widgets. Keep in mind that a single extension can be rendered in multiple locations.

Product Top Band

This location refers to the top-level band using which end-users navigate between modules/tabs in the Zoho Desk UI. Clicking the drop-down on this band displays all the extensions installed in the department. When an end-user clicks an extension on this list, the extension is displayed.

Image



Ticket Detail page

This location refers to a collapsible panel on the right side of the ticket detail page. The extension widget loads on this panel when the user clicks the Marketplace icon.



This location refers to a subtab on the ticket detail page. The extension widget loads in this location when the user clicks the extension in the more subtabs drop-down menu.




Features

Data APIs

Zoho Desk provides a set of APIs that facilitate interaction between your extension and your help desk portal. The APIs available are listed below:

Ticket Object

This object provides you with access to the various properties of a ticket. It is accessible only from the desk.ticket.detail.rightpanel and desk.ticket.detail.subtab widget locations. If you try to access a ticket property through a widget configured in the desk.bottomband location, the required data is returned only if you are on the ticket detail page. If you happen to be on a different page, the data is not returned.

  1. departmentId
  2. email
  3. subject
  4. description
  5. status
  6. dueDate
  7. threadCount
  8. isSpam
  9. createdTime
  10. modifiedTime
  11. owner
  12. id
  13. comments
  14. attachments
  15. accountName
  16. phone
  17. productName
  18. commentCount
  19. priority
  20. channel
  21. classification
  22. category
  23. subCategory
  24. contactName
  25. customFields
  26. thread
  27. threads
  28. conversation
ZOHODESK.get("ticket.").then(function(response){ //response returns the property data of the ticket }) where <property> must be replaced with the particular property or data you want to fetch

To access any property of a ticket, use the following code snippet.




Methods
The ticket object supports the following two methods:

Get ticket: Fetch a ticket along with all associated properties from the help desk portal.

ZOHODESK.get(“ticket”).then(function(response) { //response returns the ticket with all its properties })

Request:


{ "ticket": { "departmentId": "12345678901234567", "email": "youremail@domainname.com", "subject": "Faulty phone charging port", "description": "Product replacement", "status": "Open", "dueDate":"21/02/2018 12:00 PM", "threadCount": "1", "isSpam": false, "createdTime": "29/01/2018 11:55 PM", "modifiedTime": "31/01/2018 11:27 AM", "owner": "Agent Name", "accountName": "Account Name", "phone": "1234567890", "commentCount": "1", "priority": "High", "channel": "Phone", "classification": "Problem", "category": "General", "subCategory": "Sub General", "contactName": "Contact Name" }, "status": "success" }

Response:
























You can fetch specific properties of a ticket using the get method.

Get department ID: Fetch the ID of the department associated with the ticket.

ZOHODESK.get("ticket.departmentId").then(function(response){ //response returns the ID of the department associated with the ticket }) .catch(function(err){ // Error handling })

Request:



{ "ticket.departmentId": "12345678901234567", "status": "success" }

Response:




Get ticket email: Fetch the email ID associated with the ticket (Ticket creator email ID/contact email ID).

ZOHODESK.get("ticket.email").then(function(response){ //response returns the email ID associated with the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.email": "emailID@domainname.com", "status": "success" }

Response:




Get ticket subject: Fetch the subject of the ticket. 

ZOHODESK.get("ticket.subject").then(function(response){ //response returns the subject of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.subject": "Faulty phone charging port", "status": "success" }

Response:




Get ticket description: Fetch the description of the ticket.  

ZOHODESK.get("ticket.description").then(function(response){ //response returns the description of the ticket }) .catch(function(err){ // Error handling })

Request:



{ "ticket.description": "The charging port of the phone has stopped working. Customer requires a replacement.", "status": "success" }

Response:





Get ticket status: Fetch the status of the ticket.  

ZOHODESK.get("ticket.status").then(function(response){ //response returns the status of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.status": "Open", "status": "success" }

Response:





Get ticket dueDate: Fetch the due date of the ticket.  

ZOHODESK.get("ticket.dueDate").then(function(response){ //response returns the dueDate of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.dueDate": "21/02/2018 12:00 PM", "status": "success" }

Response:





Get ticket thread count: Fetch the thread count of the ticket.  

ZOHODESK.get("ticket.threadCount").then(function(response){ //response returns the thread count of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.threadCount": "1", "status": "success" }

Response:





Get ticket spam status: Returns whether a ticket is spam or not.  

ZOHODESK.get("ticket.isSpam").then(function(response){ //response returns a Boolean value that states whether the ticket is spam or not }).catch(function(err){ // Error handling })

Request:



{ "ticket.isSpam": "false", "status": "success" }

Response:





Get time of ticket creation: Fetch the time the ticket was created.   

ZOHODESK.get("ticket.createdTime").then(function(response){ //response returns the time the ticket was created }).catch(function(err){ // Error handling })

Request:



{ "ticket.createdTime": "29/01/2018 11:55 PM", "status": "success" }

Response:





Get time of ticket modification: Fetch the time the ticket was modified.   

ZOHODESK.get("ticket.modifiedTime").then(function(response){ //response returns the time the ticket was modified }).catch(function(err){ // Error handling })

Request:



{ "ticket.modifiedTime": "31/01/2018 11:27 AM", "status": "success" }

Response:





Get ticket owner: Fetch the agent to whom the ticket is assigned.    

ZOHODESK.get("ticket.owner").then(function(response){ //response returns the name of the agent assigned to resolve the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.owner": "Agent Name", "status": "success" }

Response:





Get ticket ID: Fetch the ID of the ticket.    

ZOHODESK.get("ticket.id").then(function(response){ //response returns the ID of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.id": "12345678901234567", "status": "success" }

Response:





Get ticket comments: Fetch the comments recorded on the ticket.    

ZOHODESK.get("ticket.comments").then(function(response){ //response returns comments recorded on the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.comments": { "data": [ { "modifiedTime": null, "encodedContent": "Has anyone else faced this problem before?", "commentedTime": "2018-01-08T17:25:46.000Z", "isPublic": false, "id": "2000000011023", "content": "Has anyone else faced this problem before?", "commenterId": "2000000009148" }, { "modifiedTime": null, "encodedContent": "I would like some advice ASAP.", "commentedTime": "2018-01-08T17:25:57.000Z", "isPublic": true, "id": "2000000011027", "content": "I would like some advice ASAP.", "commenterId": "1234567890123" } ] }, "status": "success" }

Response:























Set ticket comment: Asynchronously add a comment to the ticket in the product UI.   

ZOHODESK.set("ticket.comment",{"comment":"test comment test"}).then(function(response){ }).catch(function(err){ // Error handling })

Request:



Get ticket attachments: Fetch file attachments from the ticket.    

ZOHODESK.get("ticket.attachments").then(function(response){ //response returns the attachments in the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.attachments": { "data": [ { "size": "366365", "name": "pro.jpg", "creatorId": "1234567890123", "isPublic": false, "createdTime": "2018-01-08T17:29:52.000Z", "id": "1234567890123" }      ] }, "status": "success" }

Response:














Get account name from ticket: Fetch the account associated with the ticket.     

ZOHODESK.get("ticket.accountName").then(function(response){ //response returns the name of the account associated with the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.accountName": "Account Name", "status": "success" }

Response:





Get phone number from ticket: Fetch the phone number associated with the ticket.     

ZOHODESK.get("ticket.phone").then(function(response){ //response returns the phone number associated with the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.phone": "1234567890", "status": "success" }

Response:





Set phone number in ticket: Asynchronously set the phone number to the ticket in the product UI.      

ZOHODESK.set("ticket.phone",{"phone":"1234567890"}).then(function(response){ }).catch(function(err){ // Error handling })

Request:





Get product name from ticket: Fetch the product name from the ticket.      

ZOHODESK.get("ticket.productName").then(function(response){ //response returns the name of the product associated with the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.productName": "Product Name", "status": "success" }

Response:





Get comment count from ticket: Fetch the number of comments recorded on the ticket.      

ZOHODESK.get("ticket.commentCount").then(function(response){ //response returns the number of comments recorded on the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.commentCount": "2", "status": "success" }

Response:





Get ticket priority: Fetch the priority of the ticket.       

ZOHODESK.get("ticket.priority").then(function(response){ //response returns the priority status of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.priority": "High", "status": "success" }

Response:





Set ticket priority: Asynchronously set the priority of the ticket in the product UI.        

ZOHODESK.set("ticket.priority",{"priority":"High"}).then(function(response){ }).catch(function(err){ // Error handling })

Request:




Get ticket channel: Fetch information on the channel through which the ticket originated.         

ZOHODESK.get("ticket.channel").then(function(response){ //response returns the channel through which the ticket originated }).catch(function(err){ // Error handling })

Request:



{ "ticket.channel": "Phone", "status": "success" }

Response:





Get ticket classification: Fetch ticket type.        

ZOHODESK.get("ticket.classification").then(function(response){ //response returns the classification of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.classification": "Question", "status": "success" }

Response:





Set ticket classification: Asynchronously set the type for the ticket: Question, Problem, Features, and Others, on the product UI.        

ZOHODESK.set("ticket.classification",{"classification":"Problem"}).then(function(response){     }).catch(function(err){ // Error handling })

Request:





Get ticket category: Fetch the category of the ticket.         

ZOHODESK.get("ticket.category").then(function(response){ //response returns the category of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.category": "Defects", "status": "success" }

Response:





Get ticket subcategory: Fetch the sub-category under which the ticket was created.        

ZOHODESK.get("ticket.subCategory").then(function(response){ //response returns the sub-category of the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.subCategory": "Sub Defects", "status": "success" }

Response:





Get contact name in ticket: Fetch the name of the contact who sent the ticket.         

ZOHODESK.get("ticket.contactName").then(function(response){ //response returns the contact name in the ticket }).catch(function(err){ // Error handling })

Request:



{ "ticket.contactName": "Contact Name", "status": "success" }

Response:





Get customFields: Fetch the custom fields in the ticket and their corresponding values.         

ZOHODESK.get("ticket.customFields").then(function(response){ //response returns the custom fields in the ticket along with their values         }).catch(function(err){  //Error handling          })

Request:



{ "ticket.customFields": { "SecondaryContact":"1234567890" }, "status": "success" }

Response:







Get thread: Fetch a single thread from a ticket.       

ZOHODESK.get('ticket.thread', {threadId : "12345678901234567"}).then(function(res){ //response returns the thread specified }).catch(function(err){ })

Request:



{ "ticket.thread": { "channel": "EMAIL", "status": "SUCCESS", "summary": "Testing", "attachments": [ ], "author": { "name": "Firstname Lastname", "email": "emailID@domainname.com", "type": "AGENT", "photoURL": "https://desk1.portalname.com/api/v1/agent/12345678901234567/photo" }, "visibility": "public", "direction": "out", "createdTime": "2018-03-22T09:55:50.962Z", "actions": [ ], "id": "12345678901234567", "hasAttach": false, "content": "<meta /><div><div style=\"font-size: 13px; font-family: Arial, Helvetica, Verdana, sans-serif\"><div><blockquote style=\"border-left: 1px dotted rgb(229, 229, 229); margin-left: 5px; padding-left: 5px\"><div style=\"padding-top: 10px\"><div>Testing</div></div></blockquote></div></div><div><meta itemprop=\"zdeskTicket\" content=\"263f10fd68b0cc315920245c7c0aa2b93fdf0a3db99826a12352285b65f8e5fa097eaa794b5aa33edccdd6abe429590343e7d3e340e4287da6a62c59c437fb11\" /></div><br /><div>", "cc": "support@portalname.domainname.com", "responderId": "12345678901234567", "bcc": "", "to": "emailID@domainname.com", "fromEmailAddress": "\"portalname\"", "isForward": false }, "status": "success" }

Response:































Get threads: List a specific number of threads from a ticket, based on the limit defined.        

ZOHODESK.get('ticket.threads', {from : 0, limit : 10}).then(function(res){ //response returns the list of threads }).catch(function(err){ }) 

Request:

Note: from refers to the index number starting from which the resources must be fetched. limit refers to the number of resources to fetch, and its value cannot exceed 99. Either of the two parameters must be included in the API request.

{"ticket.threads" : { "data": [ { "channel": "EMAIL", "status": "DRAFT", "summary": "Some PATCHED draft thread", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "AGENT", "photoURL": "https://desk.portalname.com/api/v1/agent/12345678901234567/photo" }, "visibility": "public", "direction": "out", "createdTime": "2018-02-05T06:18:58.522Z", "actions": [ { "method": "DELETE", "rel": "delete", "href": "https://desk.portalname.com/api/v1/tickets/12345678901234567/draftReply/12345678901234567" }, { "method": "POST", "rel": "send", "href": "https://desk.portalname.com/api/v1/tickets/12345678901234567/sendDraft?draftThreadId=12345678901234567" } ], "id": "12345678901234567", "hasAttach": false, "cc": "", "responderId": "12345678901234567", "bcc": "", "to": "example2@example.com", "fromEmailAddress": "\"portalname\"", "isForward": false }, { "channel": "EMAIL", "status": "SUCCESS", "summary": "Some PATCHED draft thread", "attachments": [], "author": { "name": "Author Name", "email": "username@domainname.com", "type": "AGENT", "photoURL": "https://desk.portalname.com/api/v1/agent/12345678901234567/photo" }, "visibility": "public", "direction": "out", "createdTime": "2018-03-23T11:08:10.433Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "content": "<meta /><div>Some PATCHED draft thread<div id=\"ZDeskInteg\"><meta itemprop=\"zdeskTicket\" content=\"5daa425305ccbc60f58f122d41df729d0ced47a219d557d5da94cd732b9ba63853aa129b5170d1c4c7ac344c755fac0a7f36480e51912dd365d982aa8b5a18f1\" /></div><br /></div>", "cc": "", "responderId": "12345678901234567", "bcc": "", "to": "example2@example.com", "fromEmailAddress": "\"portalname\"", "isForward": false }, { "channel": "FEEDBACK", "status": "SUCCESS", "summary": "rated response from . Wow! You just made our day!\" That's feedback content \"", "author": { "name": "Author Name", "email": "\"Author Name\"", "type": "END_USER", "photoURL": "https://domainname.test.co.in/api/v1/portalUser/12345678901234567/photo" }, "visibility": "public", "direction": "in", "createdTime": "2018-02-07T07:07:45.133Z", "actions": [], "id": "12345678901234567", "hasAttach": false }, { "channel": "WEB", "status": "SUCCESS", "summary": "", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "END_USER", "photoURL": "https://domainname.test.co.in/api/v1/portalUser/12345678901234567/photo" }, "visibility": "public", "direction": "in", "createdTime": "2017-11-21T20:45:13.383Z", "actions": [], "id": "12345678901234567", "hasAttach": false }, { "channel": "CUSTOMERPORTAL", "status": "SUCCESS", "summary": "reply for a tickk", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "END_USER", "photoURL": "https://domainname.test.co.in/api/v1/portalUser/12345678901234567/photo" }, "visibility": "public", "direction": "in", "createdTime": "2018-01-18T14:21:12.305Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "fromEmailAddress": "username@domainname.com" }, { "channel": "FORUMS", "status": "SUCCESS", "summary": "xxx", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "END_USER", "photoURL": "https://desk.portalname.com/api/v1/portalUser/12345678901234567/photo" }, "visibility": "public", "direction": "in", "createdTime": "2017-04-12T11:51:36.352Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "fromEmailAddress": "username@domainname.com" }, { "channel": "FACEBOOK", "status": "SUCCESS", "summary": "Testing", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "AGENT", "photoURL": "https://domainname.test.co.in/api/v1/agent/12345678901234567/photo" }, "visibility": "public", "direction": "out", "createdTime": "2017-11-27T06:19:12.383Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "responderId": "12345678901234567", "facebookProfile": "FB Profile" }, { "channel": "FACEBOOK", "status": "SUCCESS", "summary": "Hi! Please share my service schedule.", "author": { "name": "Author Name", "email": "", "type": "END_USER", "photoURL": null }, "visibility": "public", "direction": "in", "createdTime": "2017-11-27T06:19:11.973Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "facebookProfile": "FB Profile Name" }, { "channel": "FACEBOOK", "status": "DRAFT", "summary": "My Facebok Draft Thread", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "AGENT", "photoURL": "https://domainname.test.co.in/api/v1/agent/12345678901234567/photo" }, "visibility": "public", "direction": "out", "createdTime": "2017-12-01T09:53:37.557Z", "actions": [ { "method": "DELETE", "rel": "delete", "href": "https://domainname.test.co.in/api/v1/tickets/12345678901234567/draftReply/12345678901234567" }, { "method": "POST", "rel": "send", "href": "https://domainname.test.co.in/api/v1/tickets/12345678901234567/sendDraft?draftThreadId=12345678901234567" } ], "id": "12345678901234567", "hasAttach": false, "responderId": "12345678901234567", "facebookProfile": "FB Profile Name" }, { "channel": "TWITTER", "status": "SUCCESS", "summary": "My refrigerator stopped working", "author": { "name": "Author Name", "email": "username@domainname.com", "type": "AGENT", "photoURL": "https://rebrand-support.test.co.in/api/v1/agent/12345678901234567/photo" }, "visibility": "public", "direction": "out", "createdTime": "2017-12-01T08:14:47.758Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "responderId": "12345678901234567", "twitterProfile": "Twitter Handle" }, { "channel": "TWITTER", "status": "SUCCESS", "summary": "I'm facing the same issue.", "author": { "name": "Author Name", "email": "", "type": "END_USER", "photoURL": null }, "visibility": "public", "direction": "in", "createdTime": "2017-11-27T06:18:25.547Z", "actions": [], "id": "12345678901234567", "hasAttach": false, "twitterProfile": "Twitter Handle" }, { "channel": "ONLINE_CHAT", "status": "SUCCESS", "summary": "", "author": { "name": "Author Name", "email": "Author", "type": "END_USER", "photoURL": null }, "visibility": "public", "createdTime": "2017-10-13T07:34:13.333Z", "direction": "in", "actions": [], "id": "12345678901234567", "hasAttach": false, "fromEmailAddress": "Author" }, { "channel": "OFFLINE_CHAT", "status": "SUCCESS", "summary": "", "author": { "name": "Author Name", "email": "Author", "type": "END_USER", "photoURL": null }, "visibility": "public", "createdTime": "2017-10-13T07:34:13.333Z", "direction": "in", "actions": [], "id": "12345678901234567", "hasAttach": false, "fromEmailAddress": "Author" }, { "channel": "ONLINE_CHAT", "status": "SUCCESS", "summary": "", "attachments": [], "author": { "name": "Author Name", "email": "Author", "type": "END_USER", "photoURL": null }, "visibility": "public", "createdTime": "2017-10-13T07:34:13.333Z", "direction": "in", "actions": [], "id": "98765432109876543", "hasAttach": false, "content": "<table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"border-top: 1px solid rgb(245, 245, 245)\"><tbody><tr><td style=\"background-color: rgb(251, 251, 251); width: 175px; max-width: 250px !important; min-width: 175px !important; overflow: hidden\"><div style=\"font-size: 12px; font-family: Arial, Helvetica, sans-serif, Tahoma; color: rgb(51, 51, 51); padding-right: 10px; text-align: right\"><i><b>Question</b></i></div></td><td style=\"border-bottom: 1px solid rgb(251, 251, 251); padding: 8px 10px 6px 12px; font-size: 12px; color: rgb(153, 153, 153); text-decoration: none\"><i>Please rate our service.</i></td></tr><tr><td style=\"background-color: rgb(251, 251, 251); width: 175px; max-width: 250px !important; min-width: 175px !important; overflow: hidden; width: 140px\"><div style=\"color: rgb(176, 176, 176); text-align: right; padding-right: 10px; font-weight: bold; font-size: 12px; font-family: Arial, Helvetica, sans-serif, Tahoma\"><div class=\"sender\"><b>Author Name</b></div></div></td><td style=\"border-bottom: 1px solid rgb(251, 251, 251); padding: 8px 10px 6px 12px\"><span style=\"color: rgb(153, 153, 153); float: right; font-family: arial; font-size: 11px; font-style: normal; max-width: 65px; min-width: 50px; visibility: visible; white-space: nowrap\">13 Oct, 1:02 PM </span><span style=\"padding-left: 2px; font: 12px Arial; color: rgb(0, 0, 0); text-decoration: none; float: left\">yes>/span><span style=\"clear: both\"></span></td></tr><tr><td style=\"background-color: rgb(251, 251, 251); width: 175px; max-width: 250px !important; min-width: 175px !important; overflow: hidden\"> </td><td style=\"border-bottom: 1px solid rgb(251, 251, 251); padding: 8px 10px 6px 12px\"><span style=\"color: rgb(153, 153, 153); float: right; font-family: arial; font-size: 11px; font-style: normal; max-width: 65px; min-width: 50px; visibility: visible; white-space: nowrap\">1:03 PM</span><span style=\"padding-left: 2px; font: 12px Arial; color: rgb(0, 0, 0); text-decoration: none; float: left\">its u again??</span><span style=\"clear: both\"> </span></td></tr></tbody></table>", "fromEmailAddress": "Author<username@domainname.com>" } ] } }

Response:



















































































































































































































































































Get ticket conversation: Fetch the entire conservation, including all threads and comments, recorded on a ticket.         

ZOHODESK.get('ticket.conversation').then(function(res){ //response returns the entire conversation recorded on the ticket }).catch(function(err){ })

Request:



{ "ticket.conversation": { "data": [ { "summary": "Testing", "cc": "support@portalname.domainname.com", "bcc": "", "visibility": "public", "author": { "photoURL": "https://desk1.portalname.com/api/v1/agent/12345678901234567/photo", "name": "Agent Name", "type": "AGENT", "email": "emailID@domainname.com" }, "channel": "EMAIL", "type": "thread", "isForward": false, "hasAttach": false, "responderId": "12345678901234567", "createdTime": "2018-03-22T09:55:50.962Z", "id": "98765432109876543", "to": "emailID@domainname.com", "fromEmailAddress": "\"portalname\"", "actions": [ ], "status": "SUCCESS", "direction": "out" }, { "modifiedTime": null, "attachments": [ ], "encodedContent": "test", "commentedTime": "2018-03-21T09:35:55.000Z", "isPublic": false, "id": "12345678901234567", "type": "comment", "content": "test", "commenterId": "98765432109876543" } ] }, "status": "success" }

Response:






































User Object

Listed below are the properties related to the user object:

  1. user
  2. isLightAgent
  3. tzoffset
  4. fullName
  5. email
  6. portals

Get user information: Fetch information of a particular user.          

ZOHODESK.get("user").then(function(response){ // response returns information about a particular user }).catch(function(err){ // Error handling })

Request:



{ "user": { "fullName": "User fullname", "email": "emailID@domainname.com", "isLightAgent": false, "tzoffset": 330, "portals": { "portalname": "Portal Name" } }, "status": "success" }

Response:












Get full name of user Fetch the full name of a particular user.           

ZOHODESK.get("user.fullName").then(function(response){ // response returns the full name of a user }).catch(function(err){ // Error Handling })

Request:



{ "user.fullName": "user full name", "status": "success" }

Response:





Get LightAgent status of user: Return whether the user is a light agent or not.         

ZOHODESK.get("user.isLightAgent").then(function(response){ // response returns the Boolean value that states whether the user is a light agent or not }).catch(function(err){ // Error Handling })

Request:




{ "user.isLightAgent": "false", "status": "success" }

Response:





Get user time offset: Fetch the time offset of a particular user. Time offset refers to the difference in time between the Coordinated Universal Time (UTC) and the current standard time in the user's time zone. The time difference is expressed in minutes.         

ZOHODESK.get("user.tzoffset").then(function(response){ // response returns the time zone offset of the user }).catch(function(err){ // Error Handling })

Request:



{ "user.tzoffset": 330, "status": "success" }

Response:





Get user email: Fetch the email id of the user.        

ZOHODESK.get("user.email").then(function(response){ // response returns the email address of the user }).catch(function(err){ // Error Handling })

Request:



{ "user.email": "emailID@domainname.com", "status": "success" }

Response:





Get user portals: Fetch the portals to which the user belongs.        

ZOHODESK.get("user.portals").then(function(response){ // response returns the portals to which the user belongs }).catch(function(err){ // Error Handling })

Request:



{ "user.portals": { "marketplacemac": "1234567" }, "status": "success" }

Response:







Portal Object

Listed below are the properties related to the portal object:

  1. plan
  2. id
  3. name
  4. customDomainName

Get portal plan: Fetch the Zoho Desk plan used in the portal.      

ZOHODESK.get("portal.plan").then(function(response){ // response returns the current Zoho Desk plan of the portal }).catch(function(err){ // Error Handling })

Request:



{ "portal.plan": "ENTERPRISE EDITION", "status": "success" }

Response:





Get portal ID: Fetch the ID of the portal.     

ZOHODESK.get("portal.id").then(function(response){ // response returns the id of the portal }).catch(function(err){ // Error Handling })

Request:



{ "portal.id": "54516290", "status": "success" }

Response:





Get portal name: Fetch the name of the portal.     

ZOHODESK.get("portal.name").then(function(response){ // response returns the name of the portal }).catch(function(err){ // Error Handling })

Request:



{ "portal.name": "portalname", "status": "success" }

Response:





Get custom domain name of portal: Fetch the custom domain name of the portal.    

ZOHODESK.get("portal.customDomainName").then(function(response){ // response returns the custom domain name of the portal }).catch(function(err){ // Error Handling })

Request:



{ "portal.customDomainName": "https://customdomainname.com",             "status": "success" }

Response:





Contact Object

Listed below are the properties related to the contact object:

  1. list
  2. info

Get all contacts: List a specific number of contacts from the help desk portal, based on the limit defined.     

ZOHODESK.get("contact.list",{'from' : 0, 'limit' : 10}).then(function(response){ // response returns the list of contacts }).catch(function(err){ // Error Handling })

Request:

Note: from refers to the index number starting from which the resources must be fetched. limit refers to the number of resources to fetch, and its value cannot exceed 99. Both parameters are optional. 

{ "contacts.list": { "data": [ { "firstName": "Firstname", "lastName": "Lastname", "email": "emailID@domainname.com", "secondaryEmail": null, "phone": null, "type": null, "ownerId": "1234567890123", "accountId": null, "account": null, "zohoCRMContact": null, "customerHappiness": { "badPercentage": "0", "okPercentage": "0", "goodPercentage": "0" }, "id": "1234567890123" }, { "firstName": "Firstname", "lastName": "Lastname", "email": "emailID@domainname.com", "secondaryEmail": "emailID2@domainname.com", "phone": "1234567890", "type": "Prospect", "ownerId": "1234567890123", "accountId": "1234567890123", "account": { "accountName": "Account Name", "website": null, "id": "1234567890123" }, "zohoCRMContact": null, "customerHappiness": { "badPercentage": "0", "okPercentage": "0", "goodPercentage": "0" }, "id": "2000000009310" }, { "firstName": "Firstname", "lastName": "Lastname", "email": "emailID@domainname.com", "secondaryEmail": null, "phone": null, "type": null, "ownerId": "1234567890123", "accountId": "1234567890123", "account": { "accountName": "Account Name", "website": null, "id": "1234567890123" }, "zohoCRMContact": null, "customerHappiness": { "badPercentage": "0", "okPercentage": "0", "goodPercentage": "0" }, "id": "123456789012" } ] }, "status": "success" }

Response:




























































Get contact info: Fetch information of a particular contact.      

ZOHODESK.get("contact.info", {'id': '1234567890123'}).then(function(response){ // response returns information pertaining to the contact specified }).catch(function(err){ // Error Handling })

Request:

Note: id is a mandatory parameter in this API request. 

{ "contacts.info": { "firstName": "Firstname", "lastName": "Lastname", "facebook": null, "twitter": null, "email": "emailID@domainname.com", "secondaryEmail": "emailID2@domainname.com", "mobile": null, "phone": null, "city": "City", "country": "Country", "state": "State", "street": null, "zip": null, "description": null, "title": "Ms", "type": "Prospect", "createdTime": "2018-01-06T06:49:27.000Z", "modifiedTime": "2018-01-09T11:58:55.000Z", "ownerId": "1234567890123", "accountId": "1234567890123", "customFields": { }, "account": { "accountName": "Account Name", "website": "http://www.domainname.com", "id": "12334567890123" }, "zohoCRMContact": null, "customerHappiness": { "badPercentage": "0", "okPercentage": "0", "goodPercentage": "0" }, "id": "1234567890123", "isDeleted": false }, "status": "success" }

Response:




































Agent Object

Listed below are the properties related to the agent object:

  1. list
  2. info
  3. signature

Note: The following APIs work only for users with admin privileges in their portal.

List all agents: List a specific number of agents from the help desk portal, based on the limit defined.

ZOHODESK.get("agent.list",{'from' : 0, 'limit' : 10}).then(function(response){ //response returns the list of agents }).catch(function(err){ // Error handling })

Request:

Note: from refers to the index number starting from which the resources must be fetched. limit refers to the number of resources to fetch, and its value cannot exceed 99. Both parameters are optional. 

{ "agent.list": { "data": [ { "zuid": "1234567", "emailId": "agentemailID@domainname.com", "status": "ACTIVE", "roleId": "12345678901234567", "profileId": "12345678901234567", "firstName": "Firstname", "lastName": "Lastname", "phone": "987654321", "mobile": "1234567890", "extn": "111", "associatedDepartmentIds": [ "12345678901234567", "12345678901234567" ], "associatedChatDepartmentIds": [ ], "photoURL": null, "id": "12345678901234567", "langCode": "en", "countryCode": "en_us", "isConfirmed": true }, ] }, "status": "success" }

Response:


























Get agent information: Fetch information of a particular agent.

ZOHODESK.get("agent.info",{"id":"12345678901234567"}).then(function(response){ //response returns information pertaining to the agent specified }).catch(function(err){ // Error handling })

Request:

Note: id is a mandatory parameter in this API request. 


{ "agent.info": { "zuid": "12345678", "emailId": "emailID@domainname.com", "status": "ACTIVE", "roleId": "12345678901234567", "profileId": "12345678901234567", "firstName": "Firstname", "lastName": "Lastname", "phone": "987654321", "mobile": "1234567890", "extn": "111", "associatedDepartmentIds": [ "12345678901234567", "12345678901234567" ], "associatedChatDepartmentIds": [ ], "photoURL": null, "id": "12345678901234567", "langCode": "en", "countryCode": "en_us", "isConfirmed": true }, "status": "success" }

Response:























Get agent signature: Fetch the signature of a particular agent.

ZOHODESK.get("agent.signature", {"id":"12345678901234567"}).then(function(response){ //response returns the signature of the agent specified }).catch(function(err){ // Error handling })

Request:

Note: id is a mandatory parameter in this API request.  


{ "agent.signature": { "signature": "
Thanks & Regards
Saravana Kumar
", "agentId": "12345678901234567", "isActive": true }, "status": "success" }

Response:











Department Object

Listed below are the properties related to the agent object:

  1. list
  2. info
  3. id

Note: The following APIs work only for users with admin privileges in their portal.

List all departments: List a specific number of departments from the help desk portal.

ZOHODESK.get("department.list").then(function(response){// response returns the list of deparments }).catch(function(err){ // Error Handling })

Request:



{ "department.list": [ { "name": "department name", "depid": "1234567890123", "agents": [ "1234567890" ], "isActive": true, "isPrivate": false } ], "status": "success" }

Response:














Get department information: Fetch information of a particular department.

ZOHODESK.get("department.info", {"id":"1234567890123"}).then(function(response){ // response returns information on the department specified }).catch(function(err){ // Error Handling })

Request:
Note: id is a mandatory parameter in this API request. 


{ "department.info": [ { "name": "department name", "depid": "1234567890123", "agents": [ "1234567890" ], "isActive": true, "isPrivate": false } ], "status": "success" }

Response:













Get ID of current department: Fetch the ID of the department in which the agent is working at the moment.

ZOHODESK.get("department.id").then(function(response){ // response returns the ID of the department in which the agent is currently working }).catch(function(err){ // Error Handling })

Request:



{"department.id":"123456789012345678","status":"success"}

Response:




Data Storage APIs 

Sometimes, the extensions you create might require data storage and retrieval capabilities. To help you in such cases, we provide a data store for extensions to set (store) and get (retrieve) data. The data can be deleted when it is no longer required. 

The following APIs provide database management functionalities to extensions. 

Get data: Fetch data from the connected database. 

ZOHODESK.get('database',{'key': '3', 'queriableValue':'test'}).then(function(response){ //response returns the value, based on the key specified }).catch(function(err){ // Error handling })

Request:
Note: Both key and queriableValue are optional parameters, but at least one of them must be included in this API request. 

{ "database.get": { "data": [ { "value": { "test": "testid" }, "queriableValue": "test", "key": "3" } ] }, "status": "success" }

Response:














Set data: Asynchronously set data in the connected database.  

ZOHODESK.set('database',{'key':'3','value': {'test':'testid'}, 'queriableValue':'test'}).then(function(response){ // response returns the value saved }).catch(function(err){ // Error handling })

Request:
Note: All three parameters--key, value, and queriableValue--must be passed in this API request. The conditions for each parameter are as follows:

{ "database.set": { "value": { "test": "testid" }, "queriableValue": "test", "key": "3" }, "status": "success" }

Response:










Delete data: Delete data from the connected database.   

ZOHODESK.delete('database',{'key':'3'}).then(function(response){ // response returns the status of deletion }).catch(function(err){ // Error handling })

Request:
Note: key is a mandatory parameter in this API request. 


{ "database.delete": { "delete": "success" }, "status": "success }

Response:







However, these APIs come with the following limitations:

Extension APIs 

These APIs fetch or set information related to the extension.

Get extension config variable: Fetch the installation parameters of the extension. In production mode, only those parameters that have the value of the secure key set to false are returned. In development mode, all parameters are returned, irrespective of the value of the secure key

ZOHODESK.get("extension.config").then(function(response){ // response returns the installation parameters of the extension }).catch(function(err){ // error handling })

Request:



{ "extension.config": [ { "name": "apikey", "mandatory": true, "type": "text", "value": "apikey", "userdefined": true, "secure": true, "default": "TestData" } ], "status": "success" }

Response:














Set value for extension config variable: Dynamically sets the value for a config variable defined in the plugin manifest file. New config variables cannot be defined using this API. 

ZOHODESK.set('extension.config', {name : 'test', value : "value"}).then(function(res){ //response returns the value saved }).catch(function(err){ })

Request:


{ extension.config: { "data": [ { "userDefined": false, "name": "test", "options": "[]", "secure": false, "mandatory": false, "value": "value", "varId": "12345678901234567" } ] }, status: "success" }

Response:













Request API

This API avoid CORS-related issues and successfully run third-party APIs from the extension.

var reqObj= { url : 'http://demo2022863.mockable.io/test', headers : { 'Content-Type' : 'application/json' }, type : 'GET', data : { 'test' : "key" }, postBody : {}, connectionLinkName: "connectionLinkName specified in the connectors section in plugin-manifest file" } ZOHODESK.request( reqObj ).then(function(response){ // Response for the url }).catch(function(err){ // Error handling })

Request













Invoke API's

Below are some extra APIs that you can use in your extension. 

ROUTE_TO

This command navigates between the multiple subtabs on the ticket detail page. Listed below are the different routes supported:

  1. ticket.suggestedArticles
  2. ticket.timeline
  3. ticket.attachments
  4. ticket.history
  5. ticket.resolution
  6. ticket.approval
  7. ticket.task
  8. ticket.timeEntry
  9. ticket.conversation
  10. ticket.thread
ZOHODESK.invoke('ROUTE_TO','ticket.attachments')

Code format:


INSERT

This command inserts content into the currently opened reply editor.  

ZOHODESK.invoke('INSERT','ticket.replyEditor', {value : "

We have dispatched the book you ordered.

"});

Code format:


Event API's

You can configure extensions to receive information when an event, such as adding a comment to a ticket or opening a different ticket occurs on the ticket detail page. 

On Adding a Comment

When a user adds a comment to a ticket, the comment_Added event is broadcast along with comment details.

App.instance.on("comment_Added", function(data){ //data gives the comment detail })

Code format:


{ commentId: "219cc630fdfdef9ad7bf564c20e4e7d0", isPublicComment: false, displayTime: "9 Jan 2018 12:25 PM", displayName: "Name", comment: "Test Comment" }

The extension then receives data in the following format.


On Moving from One Ticket to Another

When the user clicks a different ticket in the All Tickets view on the left pane, the ticket_Shift event is broadcast.  

App.instance.on("ticket_Shift", function(data){ //data provides status of ticket change as true }

Code format:


{ ticket_shifted: true }

The extension then receives data in the following format.


Multi-Widget Support

.... "widgets": [ { "location": "desk.ticket.detail.rightpanel", "name": "Client SDK", "url": "/app/app-iframe-view.html", "logo" : "./app/img/1.png", "icon" : "./app/img/2.png" }, { "location": "desk.bottomband", "name": "Client SDK", "url": "/app/app-iframe-view.html", "logo" : "./app/img/1.png", "icon" : "./app/img/1.png" } ] }, ....

As mentioned earlier, users can access an extension through more than one widget on the Zoho Desk UI. Adding multiple widgets for your extension is a simple task. All that you need to do is include the properties of each widget, separated by comma, as shown in the right panel. 

Inter-Widget Communication

In some cases where an extension has multiple widgets, communication between each widget becomes crucial. This is made possible through inter-widget communication.

App.instance.getWidgets().then(function(widgets) { siblingwidgetId = widgets[0].widgetID var siblingWidget = App.instance.getWidgetInstance(siblingwidgetId); siblingWidget.emit('event', { from: Math.random() }); });

For instance, let us say an extension has two widgets: one at desk.ticket.detail.rightpanel and the other at desk.bottomband. Data from the widget on the right panel needs to be sent to the widget on the bottomband. This requirement is achieved through the following code snippet:

Code Explanation

App.instance.getWidgets() returns the array of sibling widgets of the extension.

siblingwidgetId = widgets[0].widgetID gets the widgetID of the widget on the bottomband. Here, widgets will have only one element. Therefore, iteration is not required. 

var siblingWidget = App.instance.getWidgetInstance(siblingwidgetId) returns the whole instance of the widget on the bottomband.

siblingWidget.emit('event', {from : Math.random()}) sends the event response with data to the widget on the bottomband. 

App.instance.on('event', function(data){ // data({from : "randomnumber"}) sent from other widget });

To enable the widget on the bottomband to receive the event sent from the widget on the right panel, use the following code snippet:

Besides the main widgets, you can also display information or fetch user input through modal boxes. Modal boxes are UI elements in which users must perform a particular action as part of the overall process. As a result, users will be able to continue using the app on the main window only after performing the said action on the modal box. 

To configure a modal box in your extension, write the necessary code in the modal.html file in the project folder, and reference this file where required in your extension. 

App.instance.modal({ url: '/app/modal.html', title: "Modal box" }).then(function(modalInfo) { var modalInstance = App.instance.getWidgetInstance(modalInfo.widgetID); modalInstance.on('modal.opened', function(data) { console.log('modal opened ++++++++++++++++++') }); }).catch(function(err) { console.log(err, "Modal error"); })

Below is a sample code for a widget that invokes a modal box. 










You can configure a modal box to appear in a smaller size when invoked first and then expand to display more information. You can make this possible through the resize command.

 
ZOHODESK.invoke('RESIZE');

To include this resizing option in the modal box, use the following command in the modal.html file: