Zoho Desk Platform
Introduction

ZOHO MARKETPLACE - AN INTRODUCTION

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

Zoho Marketplace is an online store where you can find extensions that deliver business value by enhancing the core functionality of the Zoho products they use. It is similar to Google's Play Store, where one finds apps for installation and use according to their needs. Earlier, one could create extensions only for Zoho CRM, Creator, Connect, Cliq, Recruit, SalesIQ, Mail, and Reports. But now, 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 your work easier and more effective. 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.

Once 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 the Marketplace for end-users to discover and use.

To keep yourself updated about changes to Zoho Desk Extension development capabilities, such as APIs and SDKs, follow the Zoho Desk Extension Developers forum.

Quick Start

Installing the Node

$ node -v v10.x or Above

As the first step in creating an extension, install the node.js runtime environment and download node.js from here (versions above 10.X are supported). After installing node.js, verify its version using the following command:

Installing the ZET CLI

Next, you must install the Zoho Extension Toolkit (ZET) 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.23.6 or Above

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:

  • Icon and logo URLs must be relative paths. Absolute paths are notallowed.
  • All keys included by default while creating the extension must be present in the plugin-manifest file. None of the keys must be removed.

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. Depending on the computer you use, open Terminal or Command Prompt and navigate to your project folder.
  2. Execute the zet run command.
  3. If you use Mozilla Firefox, open https://127.0.0.1:5000/plugin-manifest.json in a new tab, and click Advanced ---> Accept the Risk and Continue.
  4. If you use Google Chrome, open https://127.0.0.1:5000/plugin-manifest.json in a new tab and click Advanced ---> Proceed to Unsafe. If the Proceed to Unsafe option does not appear, enable the chrome://flags/#allow-insecure-localhost Chrome flag and restart the browser.
  5. Next, login to your Zoho Desk account. If you do not have a Zoho Desk account, sign up here.
  6. On the upper-right side of the Zoho Desk screen, click the Setup icon.
    The Setup page appears.
  7. On this page, under the Developer Space section, click Build Extensions.
  8. On the Build Extensions page, click Enable Developer Mode.
    This action refreshes the page and activates the Developer Mode.

  9. dev-mode-image
  10. Now the extension is installed in your Zoho Desk portal. For example, if one of the locations of the extension is Ticket Right Panel (desk.ticket.detail.rightpanel), then the widget will load in this location.
    You can now test your extension to verify if it behaves the way you intended.

  11. ticket-right-panel-ex
  12. After testing the extension, you can disable the Developer Mode by clicking the Disable Developer Mode button on the Build Extensions page.
  13. Note: Only users with the Support Administrator user profile can build extensions.

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 Extension

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 Sigma website.
  2. Click the New Extension button.



    The upload process flow begins.

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

  • Private
  • Public

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.

In public extension, you can make it available for free or for a price. In Zoho Desk, payment for extensions is charged either per installation or per user. End-users can opt for a trial of the extension to explore its functionalities. If they are satisfied with the extension and decide to purchase it, they can choose the payment type that suits them.

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 Sigma 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.

  5. For more details, refer to the Application Submission process section.

Updating the Extension

Updating the Extension to the Zoho Desk

If 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 Sigma 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:

  • If the extension is public, the updated version is published in Marketplace.
  • If the extension is private, the updated version is approved and the installation URL is displayed on the extension detail page.

When you release a new version of your extension, the Update option for it will be visible in the user's Zoho Desk portals after a period of 24 hours. If the extension must be updated immediately after the new version is released, users can find the Update option on the detail page of the extension.

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:

  • Marketplace option in the SETUP section inside Zoho Desk.



  • Zoho Marketplace website



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.

Renaming Extensions and their locations

Renaming Extensions and their locations

Configuration

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

Plugin Manifest

MultiDC Support for Widgets

Configuring Connectors for Third-Party Services

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

  1. Create a third-party connection by performing the steps under the Connect with a custom service section in this help article.
  2. On the Connection Summary page that appears after you create the connection, click the JSON tab. Copy the code snippet under the tab.
  3. Open 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 you want.
  4. Note: 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.

Location Name
Top Band (Modules section)desk.topband
Bottom Banddesk.bottomband
Desk Telephony Extensiondesk.extension.telephony
Backgrounddesk.background
Desk Extension Preferencedesk.extension.preference
Ticket Detail Right Paneldesk.ticket.detail.rightpanel
Ticket Detail Sub-tabdesk.ticket.detail.subtab
Ticket Detail Left tabdesk.ticket.detail.lefttab
Ticket Detail More Actionsdesk.ticket.detail.moreaction
Ticket Detail Thread More Actionsdesk.ticket.thread.moreaction
Ticket Form Right Paneldesk.ticket.form.rightpanel
Contact Detail Right Paneldesk.contact.detail.rightpanel
Contact Detail Sub-tabdesk.contact.detail.subtab
Contact Detail Left tabdesk.contact.detail.lefttab
Contact Form Right Paneldesk.contact.form.rightpanel
Account Detail Right Paneldesk.account.detail.rightpanel
Account Detail Sub-tabdesk.account.detail.subtab
Account Detail Left tabdesk.account.detail.lefttab
Account Form Right Paneldesk.account.form.rightpanel

Product Level

Top Band - desk.topband

This location refers to the top band from which users navigate between Zoho Desk modules. The extensions you installed in this location will be shown up under the more icon. When user picks an extension from the more icon, it will utilise the entire screen.


Image



Bottom Band - desk.bottomband

This location refers to the space next to the Keyboard Shortcuts icon on the bottom-right side of the Zoho Desk page. When a user clicks the Marketplace icon on this location, the extensions configured here are listed. Clicking an extension on this list opens the corresponding widget on the left of the Marketplace icon.


desk.bottomband-image


Desk Telephony Extension - desk.extension.telephony

This location refers to another space next to the Keyboard Shortcuts icon on the bottom-right side of the Zoho Desk page. This location is meant exclusively for telephony-based extensions. Please note that there can be only one active telephony extension in a Zoho Desk portal.


telephony-image


Background - desk.background

This location is neither visible to end-users nor does it appear in the DOM elements. Extensions installed here will not appear anywhere, but the HTML code for them can be defined as required. The main purpose of this location is to aid inter-widget communication, which refers to the communication between two widgets when they are active. In some cases, one of the widgets might not be active. In such a scenario, data can be pushed from one widget to another using the widget configured in this location.


Desk Extension Preference - desk.extension.preference

This location refers to the Configuration tab that resides next to the General Settings tab on the extension detail page. The main purpose of this location is to get the configuration from the end-user. Extensions configured in this location are visible to users with the Support Administrator profile even if the extension visibility setting is not exclusively enabled for the profile. This location is enabled only if all other configuration is completed.


extension-pref-Image

Ticket Detail page

Right Panel - desk.ticket.detail.rightpanel

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.




Sub-Tab - desk.ticket.detail.subtab

This location refers to the sub-tab (More icon) in the ticket detail page. Clicking the icon lists the extensions installed in this location. When a user clicks an extension from this list, the extension loads in the entire sub-tab section.






Left Tab - desk.ticket.detail.lefttab

This location refers to the black, vertical strip on the left side of the ticket detail page. The Marketplace logo appears here. Clicking the logo lists the extensions installed in this location.




More Actions - desk.ticket.detail.moreaction

This location refers to the more actions icon at the top-right side of the ticket detail page. Clicking this icon displays a menu in which the extensions are listed below the other standard ticket-related actions, such as Edit, Share, Follow, Delete, and so on.






Thread More Actions - desk.ticket.thread.moreaction

This location refers to the more actions icon at the top-right side of an individual thread. Clicking this icon displays a menu in which the extensions are listed below the other standard thread-related actions, such as Reply, Forward, Print, and so on.






Ticket Form Page

desk.ticket.form.rightpanel

This location refers to the Marketplace icon at the top-right side of the Add Ticket form. Clicking this icon displays a collapsible panel that lists all the extensions configured in this location.






Contact Detail page

Right Panel - desk.contact.detail.rightpanel

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




Sub-Tab - desk.contact.detail.subtab

This location refers to the sub-tab (More icon) in the contact detail page. Clicking the icon lists the extensions installed in this location. When a user clicks an extension from this list, the extension loads in the entire sub-tab section.






Left Tab - desk.contact.detail.lefttab

This location refers to the black, vertical strip on the left side of the contact detail page. The Marketplace logo appears here. Clicking the logo lists the extensions installed in this location.




Contact Form Page

Contact Form Right Panel - desk.contact.form.rightpanel

This location refers to the Marketplace icon at the top-right side of the Add Contact form. Clicking the icon displays a collapsible panel that lists all the extensions configured in this location.


contact-form-right-panel-image

Account Detail page

Right Panel - desk.account.detail.rightpanel

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




Sub-Tab - desk.account.detail.subtab

This location refers to the sub-tab (More icon) in the account detail page. Clicking the icon lists the extensions installed in this location. When a user clicks an extension from this list, the extension loads in the entire sub-tab section.






Left Tab - desk.account.detail.lefttab

This location refers to the black, vertical strip on the left side of the account detail page. The Marketplace logo appears here. Clicking the logo lists the extensions installed in this location.




Account Form Page

Account Form Right Panel - desk.account.form.rightpanel

This location refers to the Marketplace icon at the top-right side of the Add Account form. Clicking the icon displays a collapsible panel that lists all the extensions configured in this location.


account-form-right-panel-image

Client APIs

Introduction

Get APIs

Set APIs

Data Storage APIs

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:













Get extension configured departments: This API fetches the departments configured for the extension on installation.

ZOHODESK.get("extension.departments").then(function(response){ // response returns the department configured of the extension }).catch(function(err){ // error handling })

Request:



{ "extension.departments": [{ "name": "departmentName", "id": "1234567" }], "status": "success" }

Response:














Get extension configured profiles: This API fetches the profiles configured for the extension on installation.

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

Request:



{ "extension.profiles": [ { "name": "Support Manager", "id": "1234567890" }, { "name": "Newbie Agent", "id": "1234567890" }, { "name": "Administrator", "id": "1234567890" }, { "name": "Standard", "id": "1234567890" } ], "status": "success" }

Response:




















Get extension configured users: This API fetches the users configured for the extension on installation.

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

Request:



{ "extension.users": [ "1234567890", "0987654321" ], "status": "success" }

Response:














Request API

Resource API

This API gets the resource details of the extension. Make sure the resourceName key is given in resources.json file.
Refer resourceName for more details.
Note : Response will be given against the resourceName given in the extension.

ZOHODESK.get("extension.resource", {resourceName: "field1", resourceType: "fields"}).then(function(response){ //response returns the value saved }).catch(function(err){ // error handling })

Request:


{ "status": "success", "extension.resource": { "resourceName": "field1", "id": "4000000020060", "resourceType": "fields", "apiName": "cf_counter" } }

Response:













My Custom Permission API

This API gets the permission details of logged in user.
Note : Response will be given if the permissions are configured in the extension.

ZOHODESK.get("extension.permissions").then(function(response){ //response returns the value saved }).catch(function(err){ // error handling })

Request:


{ "status": "success", "extension.permissions": [ { "apiName": "createResolution", "isEnabled": true }, { "apiName": "editResolution", "isEnabled": false }, { "apiName": "deleteResolution", "isEnabled": false }] }

Response:













Invoke API

Event APIs

Hook APIs

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.ticket.detail.subtab", "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.ticket.datil.subtab. Data from the widget on the right panel needs to be sent to the widget on the subtab. 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 subtab. 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 subtab.

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

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

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

Interface APIs

Notifications

Alerts/Confirmations

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:



















Functions

Introduction

Create Function

Edit Function

Associate Function

Function Execution

Authorizations

An extension user may need to authorize the Desk or Third party services for the developer to perform the authorized actions such as calling the APIs.

Available inbuilt authentication mode is

  • Connections


Connections

                    
Sample of Manifest with connections
{ ..., "connectors":[ { "connectionLinkName" : "test216", "connectionName" : "test", "serviceName" : "jira", "userAccess" : true, "isUserDefinedService" : false }, { "connectionLinkName" : "myconni", "connectionName" : "myconni", "serviceName" : "zlabs_integration", "userAccess" : true, "isUserDefinedService" : false, "scope" : ["ZohoCliq.Channels.All"] } ] ... }

Connections can be used for the authentication of Zoho and External Services which provides the simplified solution where the authentication process (such as OAuth Client registration, redirection) is handled internally.

Developers can create a connection in the Sigma for the existing & request for new services.

Connection Configuration JSON

After successfully adding the connection in the external Sigma , obtain the Connection Configuration JSON details of the connection and speficy it in the manifest's connectors property. Value for the connectors property should be an array of obtained Connection Configuration JSONs.














Desk Invoke API

Desk's invoke API acts as a proxy between the extension and the External Services or Desk for calling the APIs.

With Desk Invoke API,

  • Can access the Zoho Desk's APIs
  • Can access the External Services's APIs
  • Can access the Extension Data Specific APIs such as storage, configParam and log APIs

                    
INVOKE API REQUEST FORMAT:
URL : api/v1/invoke RequestMethod : POST QueryParams : orgId RequestHeaders : HASH Content-Type : application/x-www-form-urlencoded RequestBody : #INVOKE_API_REQUEST_PAYLOAD.
INVOKE API RESPONSE FORMAT:
ResponseCode : 200 Content-Type : application/json Response : #INVOKE_API_RESPONSE_OBJECT

Using Desk Invoke API

The query parameters such as orgId , securityContext and headerparam HASH are required for calling Invoke API . orgId & securityContext will be provided by desk during the Platform event callbacks. HASH should be generated using the SECRET and the Request URL inputs. Refer Generating Hash for Invoke API

#INVOKE_API_REQUEST_PAYLOAD

FieldRequiredTypeDescription
securityContext yes string An Extension specific encrypted token that is used for identifying & authenticating the extension while calling the invoke API.
SecurityContext can be obtained during Platform event callbacks
requestURL yes string URL to be invoked.
requestType yes string HTTP method for invoking the
requestURL
For example,
  • GET
  • POST
  • PATCH
  • PUT
  • DELETE
postBody yes string Payload or body to be sent while invoking the requestURL.
headers yes string Headers to be sent while invoking the requestURL.
queryParams yes string QueryParams to be sent while invoking the requestURL.
connectionLinkName yes string If the authorization needs to be applied from the connections while invoking the requestURL, specify the unique connection name provided by the DRE.

                    

Sample of Invoke API HASH Generation

If manifest.secret => "my_secret_key_238392" For Sample Invoke API Inputs => requestURL = https://api.google.com/test requestType = POST queryParams = {} postBody = {} headers = {"orgId":376723} connectionLinkName = myConnectionLinkName (*ignore what you don't need)' Hash generation would be => let stringToHash = 'requestURL=https://api.google.com/test&requestType=POST&queryParams={}&postBody={}&headers={"orgId":376723}&connectionLinkName=myConnectionLinkName' then, generated HASH = hmac_sha256 ( stringToHash, "my_secret_key_238392" ); *Note: While generating HASH, only include the parameters which will be used in the
invoke API. Order of the fields while generating hash should be exactly
1.requestURL, 2.requestType, 3.queryParams, 4.postBody, 5.headers, 6.connectionLinkName and you can ignore the fields which you don't send.

Generate Hash for Invoke API

To call invoke API, HASH is mandatory. Hash is used to verify the invoke API call was originally made by the extension developer. HASH is an HMAC sha256 encrypted string with the key as app's secret (manifest.secret) provided in the manifest and the input as invokeAPI's payload.

Desk also will generate the HASH with the shared app's secret with the provided payload in the invoke API and will match the provided HASH in the desk invoke API's header. If the HASH does not match with the desk generated HASH, then the invoke API will not be processed.

The same process of authentication can be used by the extension during the extension callback events to verify the callback was originally sent by the desk.









Specifying Placeholders in Invoke API

You can specify configParams, authentication details as placeholders while calling the desk invoke API. The placeholders will be replaced with the original values before sending the request to requestURL.

Supported placeholders

Placeholder SyntaxLocation(s)Description
InstallationId{{PROPERTY}} requestURL,
queryParams,
requestHeaders
eg: https://desk.zoho.com
/api/v1/installations/
{{installationId}}/storage
Config
Params
{{PROPERTY}} requestURL,
queryParams,
requestHeaders
Name of
Config Param
eg : {{jiraAuthKey}}
resourceName{{RESOURCETYPE.RESOURCENAME.ID}} requestURL,
queryParams,
postBody,
requestHeaders
Get Field
eg : https://desk.zoho.com/api/v1/
organizationFields/{{fields.field1.id}}
resourceName{{RESOURCETYPE.RESOURCENAME.APINAME}} requestURL,
queryParams,
postBody,
requestHeaders
Set Field
eg : "cf": {
"{{fields.field1.apiName}}": "Testing"
}
                    
Sample of Specifying Connection in invokeAPI payload ... requestURL = https://api.google.com/test connectionLinkName = googleConnection ...

Specifying Authentication Details in Invoke API

Invoke API applies the authentication details specified while calling the API, find the below table for specifying the authentication details while calling the invoke API.

Auth TypeWhere to specify
( Parameter Name )
Description
connections payload (connectionLinkName) Name of the connectionLinkName has to be given in the query parameter
connectionLinkName while calling the invoke API.

                    
Sample Response : { "responseHeaders" : { "Cache-Control" : "private,no-cache,no-store,max-age=0,must-revalidate", "Set-Cookie" : "drecn=9e1f7200-bcdf-426d-9628-79ff4e9241c8; Path=/; Secure", "Vary" : "Accept-Encoding", "Expires" : "Thu, 01 Jan 1970 00:00:00 GMT", "X-XSS-Protection" : "1", "Content-Type" : "application/json;charset=utf-8" }, "response" : "{\"data\":[{\"ticketNumber\":\"176\",\"customerResponseTime\":\"2014-03-22T05:05:08.471Z\",\"productId\":null,\"contactId\":\"1892000000045028\",\"subject\":\"from forum\",\"dueDate\":\"2016-06-01T14:04:07.000Z\",\"departmentId\":\"1892000000006907\",\"channel\":\"Forums\",\"threadCount\":\"72\",\"priority\":\"High\",\"assigneeId\":\"1892000000056007\",\"closedTime\":null,\"commentCount\":\"0\",\"phone\":null,\"contact\":{\"firstName\":\"\",\"lastName\":\"as\",\"phone\":null,\"id\":\"1892000000045028\",\"type\":null,\"email\":\"manojkumar.s+4444@zohocorp.com\",\"account\":{\"website\":\"qwe.com\",\"accountName\":\"Man_Account\",\"id\":\"1892000000980421\"}},\"createdTime\":\"2014-03-06T09:49:50.000Z\",\"id\":\"1892000000094004\",\"email\":\"example@example.com\",\"status\":\"Open\"}]}", "statusCode" : "200" }

#INVOKE_API_RESPONSE_OBJECT

FieldTypeDescription
statusCode integer Status Code from the requestURL by the invoke API request.
response string Response from the requestURL by the invoke API request.
responseHeaders string Response headers sent by the requestURL.

Extension Data Specific APIs

The following are the APIs available to the extension that can be accessed using Desk Invoke API. InstallationId wont be provided to the developers, instead he has to use installationId placeholder in Invoke API to call the apis.

  • Storage API
  • Configuration Param API
  • Log API
  • My Custom Permission API

Storage API

Extensions can make use of Storage API to access & modify data from the extension's DB storage. The available storage API 's are,

  • Add data to storage
  • Get data from storage
  • Delete data from storage
                    
#STORAGE_DATA_OBJECT { "key" : "color-red-data-id-278783", "queriableValue" : "color-red-datas", "value" : { "myResult" : "Diluted solution for red color experiment 128ml " } }

#STORAGE_DATA_OBJECT

Every storage object has the following properties.

FieldTypeDescription
key string Key for the value which can be used to lookup.
value JSONObject Specifies the value that needs to be stored for the given key.
queriableValue string Used to group the multiple storage data. Specifies a common lookup group of the given key-value pair which will be useful for lookup from the database.
                    
Add data to storage: Request Format:
URL : https://desk.zoho.com/api/v1/installedExtensions/{{installationId}}/storage OAuth Scope : Desk.extensions.CREATE RequestMethod : POST RequestHeaders : orgId, Authorization Content-Type : application/json RequestBody : #STORAGE_DATA_OBJECT.
Response Format:
ResponseCode : 200 Content-Type : application/json Response : #STORAGE_DATA_OBJECT

Add data to storage

Use this API to add data to the extension storage.


















                    
Get data from storage: Request Format:
URL : https://desk.zoho.com/api/v1/installedExtensions/{{installationId}}/storage OAuth Scope : Desk.extensions.READ RequestMethod : GET RequestHeaders : orgId, Authorization QueryParams : key, queriableValue, from, limit
Response Format:
ResponseCode : 200 Content-Type : application/json Response : JSONObject with data property containing the result as array of #STORAGE_DATA_OBJECT.

Get data from storage

Use this API to get data from the extension storage with the matching criteria.


















                    
Delete data from storage: Request Format:
URL : https://desk.zoho.com/api/v1/installedExtensions/{{installationId}}/storage OAuth Scope : Desk.extensions.DELETE RequestMethod : DELETE RequestHeaders : orgId, Authorization QueryParams : key
Response Format:
ResponseCode : 200

Delete data from storage

Use this API to delete data from the extension storage specifying the key.


















Configuration Param API

Extensions can make use of Configuration Param API to access & modify the extension's config params. The available storage API's are,

  • Add config params
  • Get config param
                    
#CONFIG_PARAM_API_REQUEST_OBJECT { "variables" : [ { "name" : "configParam1", "value" : "value for the configparam 1" }, { "name" : "configParam3", "value" : "value for the configparam 3" } ] } #CONFIG_PARAM_API_RESPONSE_OBJECT { "data" : [ { "defaultValue" : "default1", "userDefined" : true, "name" : "variable1", "options" : "[op1, opt2]", "secure" : true, "type" : "text", "mandatory" : false, "value" : "testing", "varId" : "4000000011017" } ] }

#CONFIG_PARAM_API_REQUEST_OBJECT

FieldTypeDescription
variables JSONArray <#CONFIG_PARAM> Array of config params to be saved in desk

#CONFIG_PARAM

FieldTypeDescription
name string Name of the config param
value string Value of the config param






















                    
Add config params: Request Format:
URL : https://desk.zoho.com/api/v1/installedExtensions/{{installationId}}/configParams OAuth Scope : Desk.extensions.CREATE RequestMethod : POST RequestHeaders : orgId, Authorization Content-Type : application/json RequestBody : #CONFIG_PARAM_API_REQUEST_OBJECT.
Response Format:
ResponseCode : 200 Content-Type : application/json Response : #CONFIG_PARAM_API_RESPONSE_OBJECT

Add or update config params

Use this API to add or update config params.















                    
Get config params: Request Format:
URL : https://desk.zoho.com/api/v1/installedExtensions/{{installationId}}/configParams OAuth Scope : Desk.extensions.READ RequestMethod : GET RequestHeaders : orgId, Authorization
Response Format:
ResponseCode : 200 Content-Type : application/json Response : #CONFIG_PARAM_API_RESPONSE_OBJECT

Get config params

Use this API to get extension's config params.
















Extension Log APIs

Extensions can make use of Log API to log the extension processes. Logs can be viewed on customer's support portal.

Logs will expire after 3days.

Path to Logs:

Parent Logs List:

Sub Logs List:

During development, logs are loaded in the developer's portal.

The param - reference is a random string that is used to group multiple logs. If multiple logs are grouped using reference, the first log will be the parent log and the rest will be sub logs. Developer can group a maximum of 10 logs using a reference. Means, a parent log can have 9 sub logs as maximum.

If the logs are created without reference, they are considered as parent logs.

The available APIs for Logs are,

  • Add a Log
                    
#EXTENSION_LOG_OBJECT { "reference" : "1d8bd6c8-5424-11e8-9c2d-fa7ae01bbebc", "description" : "jira issue is created with id = 10223", "installationId" : "112343231355", "title" : "created a jira issue" } #LOG_API_RESPONSE_OBJECT { "parentLogId" : "4000000022003", "extensionName" : "Jira", "description" : "jira issue is created with id = 10223", "logId" : "4000000023001", "installationId" : "112343231355", "title" : "create jira issue", "logTime" : "2018-05-10T07:33:13.000Z" }

#EXTENSION_LOG_OBJECT

FieldTypeDescription
reference string a UUID string used to group multiple logs. Logs having the same reference key will be stored as a single log.
description string Log message.
installationId long The id of the installed extension
title string Title of the log














                    
Add a log: Request Format:
URL : api/v1/extensionLogs OAuth Scope : Desk.extensions.CREATE RequestMethod : POST RequestHeaders : orgId, Authorization Content-Type : application/json RequestBody : #EXTENSION_LOG_OBJECT.
Response Format:
ResponseCode : 200 Content-Type : application/json Response : #LOG_API_RESPONSE_OBJECT

Add a Log

Use this API to add extension logs.















My Custom Permission API

Use this API to retrive the permission details of logged in user.

                        
#MYPERMISSION_DATA_OBJECT { "apiName" : "createResolution", "isEnabled" : true }

#MYPERMISSION_DATA_OBJECT

Every permission object has the following properties.

FieldTypeDescription
apiName string apiName for the permission which can be used to lookup.
isEnabled Boolean Specifies whether permission is enabled or not.
                                
Get my custom permission: Request Format:
URL : https://desk.zoho.com/api/v1/installedExtensions/{{installationId}}/myCustomPermissions OAuth Scope : Desk.extensions.READ RequestMethod : GET RequestHeaders : orgId, Authorization
Response Format:
ResponseCode : 200 Content-Type : application/json Response : JSONObject with data property containing the result as array of #MYPERMISSION_DATA_OBJECT.

Get permission data

Use this API to get permission details of logged in user.


















Platform Event Callbacks

                    

plugin-manifest.json

... "callbackListener":{ "onZohoAuthorise": "https://zohodeskapp.com/authorized.php", "onConfigParamAdd": "https://zohodeskapp.com/adjustfiler.php", "onUninstall": "https://zohodeskapp.com/revokeWebhook.php" }, ...

Marketplace supports callbacks for extension's events. Developer can subscribe to the supported events and when the extension event is triggered, callbacks are invoked.

Supported Platform Event Callback's are,

  • onInstall
  • onZohoAuthorise
  • onTPAAuthorise
  • onTPARevoke
  • onUpdate
  • onConfigParamAdd
  • onConfigParamDelete
  • onUninstall

Subscribing to the Events

Extension manifest's callbackListener property is used for declaring the callbacks for the extension's events. To subscribe to an event, specify the callback URL in the manifest for the callbackListener's respective event.

                    
Event Callback Request
URL : manifest.callbackListener.{eventName} RequestMethod : POST RequestHeaders : HASH Content-Type : application/json RequestBody : JSONObject in #EVENT_CALLBACK_PAYLOAD_FORMAT format.
EVENT_CALLBACK_URL https://zohodeskapp.com/authorized.php
EVENT_CALLBACK_HEADERS { "HASH" : "xxxxxxxxx" }
EVENT_CALLBACK_PAYLOAD_FORMAT { "event" : "onZohoAuthorise", "orgId" : 387238, "securityContext" : "2398deio3qwnx3c9xwi3nc3njkh9jfico" }

Event Callback Request

Whenever the extension event occurs, the callback URL is triggered with security parameters which can be used to call the authenticated APIs.

#EVENT_CALLBACK_PAYLOAD_FORMAT

FieldDescription
event Name of the event triggered the callback.

Possible values are,
  • onInstall
  • onZohoAuthorise
  • onTPAAuthorise
  • onTPARevoke
  • onUpdate
  • onConfigParamAdd
  • onConfigParamDelete
  • onUninstall
orgId orgId of the user's organisation.
securityContext securityContext which can be used for calling Desk's invoke API.

Events


onInstall

onInstall will be triggered when the customer installs an extension. The developer can subscribe to the event with the URL and perform his logic.

Example usage

Creating a Third party resource once the customer installs the extension.


onZohoAuthorise

Once the end user installs the extension, he needs to authorize the desk & TPA (say jira). onZohoAuthorise will be triggered when the customer authorize the DESK. The developer can subscribe to the event with the URL and perform his logic.

Example usecase

Creating a Zoho Desk webhook once the desk authorization is completed.


onTPAAuthorise

The event will be triggered once the user authorize the Third party app.

Example usecase

Subscribing or creating a webhook in third party service.


onTPARevoke

The event will be triggered once the user revoke the Third party app authorization.

Example usecase

Revoking or deleting the added webhooks in the third party services.


onUpdate

The event will be triggered when the user upgrade the extension.

Example usecase

Adding or Updating config params.


onConfigParamAdd

The event will be triggered when the customer adds configuration params in the extension.

Example usecase

In jira extension, when customer adds configuration params such as domain, jiraAuthKey , developer shall create a jira webhook against the jira account.


onConfigParamDelete

The event will be triggered when the customer adds configuration params in the extension.

Example usecase

In jira extension, when customer deletes configuration params such as domain, jiraAuthKey , developer shall delete jira webhook in the jira account.


onUninstall

The event is triggered when customer uninstall the extension.

Example usecase

Operations to be performed during un-installation such as deleting webhooks.

Including Zoho Desk Resources

You can also include Zoho Desk resources, such as fields, webhooks, custom permissions, and channel integrations that can be used within the extension by defining in resources.json

For instance, if you want to create a field to be used in your extension, you have to use the organization fields API and manually associate the extension departments to the fields. This complicates the code logic of the extension and makes it difficult to manage it. You can avoid this complication by including Zoho Desk's resources in your extension's resources.json, thereby saving development time and effort substantially.

Among resources, fields are extension-specific, which means they are shared among multiple installation instances in the same portal. The other resources - webhooks, custom permissions, and channel integrations - are installation-specific, which means they are valid only in the particular installation instance.

resourceName

Each resource you create must have a unique identifier, which must be specified using the resourceName key. The resourceName(s) specified should be unique across the extension and this is validated before the extension is made available on the Marketplace.The resourceName you assign serves as the unique identifier across all organizations that install your extension.
To include a resource in your extension, you must mention its resourceName value in the resources.json file in the extension bundle.Currently, this key is supported only for fields and webhooks.


How it works?

When you define a resourceName in the resources.json file, the ID and apiName (if available) of the resource are also mapped to it automatically. After this, you can use the ID and/or apiName (if available) in APIs related to the resource, as required. For instance, if you are in need of apiName of a created field, you can use the resourceName value of the field to retrieve its apiName.

Retrieving the ID and apiName of a resource : Using the resourceName value, you can retrieve the ID and apiName of a resource in one of the following ways:
1. Through a merge field in the invoke API, or
2. Using the client SDK

1. Through a merge field in the invoke API
In this method, you must specify the resourceName value in the Desk's invoke API in the following format.
{{resourceType.resourceName.id}} or {{resourceType.resourceName.apiName}}.
Refer Specifying Placeholders in Invoke API.
Placeholders Details :
resourceType should be fields or webhook, based on your use case.
id returns the fieldId or webhookId, based on the value in resourceType.
apiName returns the apiName of the resource. it is applicable to fields.

2. Using the client SDK
In this method, you must use the Resource API for retrieving resource details.

Including Fields in Your Extension

                

resources.json

... { "fields": [{ "resourceName": "field1", "module": "tickets", "displayLabel": "Counter", "type": "Text" "maxLength": "100" }] }, ...

All fields that can be created using the Create field REST API are supported in extensions.
However, please keep in mind the following points:
1. resourceName key is mandatory in resources.json. Refer resourceName.
2. Make sure to not pass the layoutId key in the extension code because layoutId value is automatically chosen from the department associated with the extension. This means that the new field is mapped to the default layout configured for the department.

To include custom fields in your extension, add the code snippet to the resources.json file.

Any field you include in your extension will be added to the user's Zoho Desk portal on the very first installation of the extension. Subsequent installations map to the fields created already. The fields are deleted from the portal on the last uninstallation of the extension.
You can include a maximum of 10 custom fields in an extension.

Extension webhook

                    

resources.json

... "webhook":{ "resourceName": "webhook1", "url": "https://demowebhook.com/callbackurl", "name": "Demo extension webhook", "description": "Demo extension webhook listen to ticket events", "subscriptions":{ "Ticket_Add":null, "Ticket_Update":{ "includePrevState":true }, "Ticket_Thread_Add":null, "Ticket_Comment_Add":null, "Ticket_Comment_Update":null } "ignoreSourceId":"2df92c1a-973a-48f5-95b7-5792c68b9c36" }, ...
Sample of Manifest entry with Zoho Authorization - using Connnections (Desk.events.ALL scope should be included in connection scope list)
{ ..., "zohoAuthorisation" : { "type" : "connectors", "connectionLinkName" : "test12345", "connectionName" : "Webhook zoho desk", "serviceName" : "Zoho Oauth", "userAccess" : true, "scope" : ["Desk.events.ALL"], "isUserDefinedService" : false }, ... }

Marketplace supports Extension Webhook , which will allow a market place app to create extension specific desk webhooks. Extension webhook access is restricted to the extension app alone so that the normal user can't make any changes on these webhooks.

An extension developer can specify the webhook details in resources.json file. Extension webhooks will be created on authorising the extension and will be deleted on uninstalling the extension. We will apply department filtering on webhook events based on the departments choosed in the extesnion configuration.

On subscribing extension webhook we will append the orgId and securityContext to the webhook callback url. You can use this information to make API calls using Desk's invoke API.

Note:Extension webhook is allowed only for org based extensions

How to handle Authorisation

To use extension webhook you should include the webhook specific scope Desk.events.ALL in the authorisation scope list and the authorisation should be defined using the key zohoAuthorisationin plugin-manifest file.



#WEBHOOK_FIELDS

(Refer Webhook's Attribute section to know more about webhook fileds.We will apply department filtering on webhook events based on the departments choosed in the extesnion configuration. Kindly ignore the departmentIds key while giving the subscription details in resources.json file.)

FieldRequiredTypeDescription
resourceName yes string Unique indentifier for created webhook.Refer resourceName.
url yes string Server endpoint to which event information must be sent.
name yes string Name of the webhook.
description no string Description of the webhook
ignoreSourceId yes string Client ID exempted from triggering webhooks. The value of this attribute must always be a UUID. For information on how to use this attribute, refer to the Ignoring Webhook Events section.
subscriptions yes JSONObject Events that you want to subscribe to. To know about the supported events and its payload refer Event Supported.

Introduction

Channel Integration lets you to sync data such as tickets, threads and contacts between Zoho Desk and External Services. It also lets the agents to send replies to the queries on external platforms directly from the desk. Channel Integration can be achieved by ZohoDesk Marketplace app which must act as a bridge between External Service and the Zoho Desk.

Marketplace App with Channel Integration:

Marketplace App which supports the channel integration is responsible for

  • Extracting data from external service and supply to the Desk.
  • Two-way conversion - Converting the external data into desk compatible format & Converting desk reply into external service compatible format. Periodically supply updated data to the desk.
  • Add or update new replies in the external service when a reply is pushed from the desk.
  • Redirect to the external resource when requested by the desk.

Configuration

Requirements:

  • Create a ZohoDesk Marketplace App with specifying channel properties as a resource in resources.json. resources.json should be created on app root folder.
  • If your application has an authentication process, Register an OAuth Client in the External Service and get client_id and client_secret if needed.
  • Create an endpoint to provide data from external service to desk during periodic requests produced by Desk.
  • Create an endpoint which can receive new replies and send it to the External Service, when an agent reply is sent from the desk.
  • Create an endpoint which can redirect the user to the respective External Service's entities such as tickets, threads and user profiles.
                    

resources.json

... "channel": { "resourceName" :"youtube_app", "channelLogoPath" : "/app/img/youtube_logo.png", "acceptAttachments" : false, "updateRecords" : true, "contentTypes" : ["text/plain","text/html"], "redirectUrl" : "https://zohodeskapp.example.com/youtube/handleRedirect", "includeQuotedMessage": false, "sync": { "push": "https://zohodeskapp.example.com/youtube/handlePull", "pull": "https://zohodeskapp.example.com/youtube/handlePush" } } ...

resources.json

Channel configuration in the resources.json specifies the settings of the channel and the endpoints to pull or push the data for syncing. The params to be specified in the manifest are listed below.

#CHANNEL_INTEGRATION_CONFIGURATION

FieldRequiredTypeDescription
sync yes JSONObject SYNC_OBJECT Sync property of the channel defines the endpoints that are used for handling data sync.
channelLogoPath yes string (URL) Relative Path of the channel's logo image in the app directory.

Logo Specification:
image-format : png, jpg
max-size : 500kb
redirectUrl string (URL) URL which can redirect the user to the external resource of an entity. Refer Source Redirection
updateRecords boolean Specifies whether the replies of this channel can be updated.
Default : false
acceptAttachments boolean Specifies whether attachments can be added to the replies of this channel.
Default : false
includeQuotedMessage boolean Specifies whether it is advisable to add the previous replies as quoted to the replies while replying for this channel.
Default : false
contentTypes JSONArray <string> Specifies the allowed/supported content types (MIME types) for the replies of this channel.
Default : text/plain

Allowed Values :
  • text/plain
  • text/html

Sync Object

FieldRequiredTypeDescription
push yes string (URL) An endpoint to accept the replies from the desk by agent to process them and update in the external service.
Refer Push Request from Desk
pull string (URL) An endpoint which supplies updated external data when desk periodically requests.
Refer Pull Request from Desk

Sync (Data Transfer)

Desk offers the below methods to perform two-way data syncing between Desk & External Service.


Overriding read-only fields

An important usage of the syncing via channel integration is, some of the read-only system-computed fields such as createdTime, modifiedTime and direction of the thread can be specified and overridden with the original value in the external service.

                    
#SYNC_RESPONSE_OBJECT
{ "channelState":"{\"my_pending_data\":\"298092,289782,2767\"}", "data":{ "tickets": [ #SYNC_TICKET_OBJECT, #SYNC_TICKET_OBJECT, #SYNC_TICKET_OBJECT, ... max 1000 ], "threads": [ #SYNC_THREAD_OBJECT, #SYNC_THREAD_OBJECT, #SYNC_THREAD_OBJECT, ... max 1000 ] } }

#SYNC_RESPONSE_OBJECT

Desk accepts data to be synced in the below format during pull-request from desk and push-data to desk operation.

FieldRequiredTypeDescription
channelState string Value to be stored in the app's channelState configParam. Can be used to store the state of the channel sync progress.
Refer Channel State
data yes JSONObject <#SYNC_DATA_OBJECT> Contains the data to be imported from the external service, converted to desk compatible format. Supported properties are,
  • tickets
  • threads

#SYNC_DATA_OBJECT

Data format to be specified in the sync response's data property.

FieldRequiredTypeDescription
tickets JSONArray (1000) <SYNC_TICKET_OBJECT> Array of ticket properties to be imported.
threads JSONArray (1000) <SYNC_THREAD_OBJECT> Array of thread properties to be imported.
                    
Example of #SYNC_TICKET_OBJECT
{ "data":{ "tickets":[ { "extId":"whatsapp:+919994411345", "subject":"How to reset the configuration?", "createdTime":"2018-09-10T13:34:26.000Z", "actor": #SYNC_ACTOR_OBJECT, "extra": #SYNC_EXTRA_OBJECT }, ... ], "threads":[] } }

Create or Update Tickets in Desk

Channel integration lets you create and update tickets for external resources. To import tickets to the desk, the details of the ticket has to be given in the #SYNC_TICKET_OBJECT format to the pull-request from desk & push-data to desk response's data.tickets property.

#SYNC_TICKET_OBJECT

FieldRequiredTypeDescription
extId yes string Unique ID of the ticket in the external service. Refer External ID
actor yes JSONObject #SYNC_ACTOR_OBJECT Details about the author.
subject yes string (255) Details about the author.
extra yes JSONObject #SYNC_EXTRA_OBJECT Extra information about the ticket for the extension.
createdTime Timestamp ISO Format Created time of the ticket.
email string EMail ID of the ticket.
phone string Phone number of the ticket.
description string Description of the ticket.
status string Status of the ticket.
category string Ticket category.
subCategory string Ticket sub category.
resolution string Resolution of the ticket.
dueDate Timestamp ISO Format Due date for resolving the ticket.
priority string Priority of the ticket.
classification string Classification of the ticket.
customFields JSONObject Custom fields in the ticket.
assigneeId long ID of the agent to whom the ticket is assigned.
teamId long ID of the team assigned to resolve the ticket.
productId long Product to which the ticket is mapped.

External ID

ID of the resource on external service. External ID is the value which acts as a unique identifier of the resource on the external resource. The extId property plays a significant role in identifying the corresponding desk entity of the external resource during sync. If there is no entity found for the given extId of the channel in the desk, a new entity is created otherwise the existing entity which has the extId of the channel is updated. Allowed characters : A-Z a-z 0-9 @ $ & + : . { } ( ) # - _ +

For example

If we consider a Facebook post, every Facebook post has a unique ID (extId). When an external resource of Facebook service with extId "298393" is submitted to create a ticket in desk, if any existing ticket with Facebook channel and the same extId found then the ticket is updated with given data, otherwise a new ticket is created with facebook channel and given extId.


Adding External Attachments

If any external attachments need to be added to the tickets/threads, it has to be given as a JSON array of URLs which will be downloaded and attached to the tickets. The downloading of the attachments and adding to the tickets are asynchronous so that failure of attachments does not interrupt the process of adding/updating the tickets or threads.

For example

A facebook comment may contain images that you want to add as a thread.


                    
Example of #SYNC_THREAD_OBJECT
{ "data":{ "threads":[ { "extId":"SMa8974b1b935d957ffd9", "extParentId":"+123456789", "createdTime":"2018-09-10T11:54:03.000Z", "content":"What surprised", "direction":"in", "from":"+00032882", "to":["+00000273637"], "canReply":true, "extra": #SYNC_EXTRA_OBJECT, "actor": #SYNC_ACTOR_OBJECT }, ... ], "tickets":[ { "extId":"+123456789", "subject":"Knew he didnt know, i never knew a lot too!", "createdTime":"2018-09-07T14:02:27.000Z", "extra": #SYNC_EXTRA_OBJECT, "actor": #SYNC_ACTOR_OBJECT }, ... ] } }

Create or Update Threads in Desk

Channel integration lets you to add threads or replies from the external service. To import threads, provide the threads details in the #SYNC_THREAD_OBJECT format to the pull-request from desk & push-data to desk response's data.tickets property.

#SYNC_THREAD_OBJECT

FieldRequiredTypeDescription
extId yes string Unique ID of the thread in the external service. Refer External ID
extParentId yes string Parent Entity's ID of the thread in the external service.
Threads having the same parentId will be grouped under the same ticket which's extId is equal to the parentId. Refer External Parent ID
actor yes JSONObject #SYNC_ACTOR_OBJECT Details about the author.
content yes string Content of the thread.
direction string Specifies the direction of the thread. Supported Values are
  • in (incoming thread)
  • out (outgoing thread)
extra JSONObject #SYNC_EXTRA_OBJECT Extra information about the thread for the extension.
attachmentUrls JSONArray <string> Urls of the attachments to be added to the thread. Refer Adding External Attachments
createdTime Timestamp ISO Format Created time of the thread.
modifiedTime Timestamp ISO Format Modified time of the thread.
canReply boolean Specifies whether replies can be added to this thread.
contentType string Content-Type of the content of the thread. Supported Values are
  • text/plain
  • text/html
from string From address of the thread.
Default : Channel Name
to JSONArray <string> Direct Recipients of the thread
cc JSONArray <string> cc'ed Recipients of the thread
bcc JSONArray <string> bcc'ed Recipients of the thread

External Parent ID

This constraint is used for grouping multiple threads under a single ticket. extParentId contains the parent ID of the external resource in external service. For a thread external resource, extParentId is useful for identifying the correct ticket that the reply has to be added in the desk. Whenever an extParentId for a thread resource is given, a thread is added for the ticket that has the given extParentId as extId. If none of the ticket's extId matches the given extParentId then the thread will not be added.

For example

If we consider a facebook-post-comment, extParentId will be the ID of the facebook post. So that comments having the same externalaParentId will be grouped under the same ticket which has the extId.


                    
SYNC ACTOR OBJECT Sample:
{ "name" :"John Snow", "displayName" :"John Snow @johnstark", "email" :"john@gmail.com", "phone" :"+918637436803", "extId" :"39jdiwkndw3ninj", "photoURL" :"https://example.com/profile/39jninj/photo.jpg" }

#ACTOR_OBJECT

Actor object defines the properties of the author of the resource (i.e by whom this resource was made) on the external service.

FieldRequiredTypeDescription
extId yes string Unique ID of the person in the external service. Used for contacts profiles sync.
name yes string Name of the person in the external service.
displayName string Name to display on contact's detail page. If not provided, defaults to name
email string Email ID of the author on external service. If provided, this profile will be added under the contact who have the same Email Id.
phone string Phone number of the author on external service. If provided, this profile will be added under the contact who have the same Phone Number.
photoURL string <URL> URL of the author's photo on external service.

Providing app specific custom data for resources

Apps may need to store some extra details about a particular resource in addition to the desk supported standard fields of an entity.
Place holders can be given for any of the Extra-Object's properties which will be replaced with the original values of the respective entities. For supported placeholders refer Desk Resource Template Placeholders

Example

An app developer may need to store likes and share counts of a facebook post which needs to be added as a ticket or thread in the desk so that the app may show that information in the desk widgets or may need to show some actions prior to that information.


                    
SYNC EXTRA OBJECT Sample:
{ "key" :"Post-{{ticket.id}}-Comment-{{thread.id}}-Details", "queriableValue" :"Post-{{ticket.id}}-Details" "value" :{ "likes":3809, "comments":453 } }

#SYNC_EXTRA_OBJECT

FieldRequiredTypeDescription
key yes string Value for the key property can be a templated string with supported placeholders.
Key for which the given value has to be stored in the DB storage. Refer extra.key
value yes JSONObject Specifies the value that needs to be stored for the given template key.
queriableValue yes string Specifies a common lookup group of the given key-value pair which will be useful for lookup from the database.

Desk Resource Template Placeholders

Developer may not know the values of the resource but might want to make use of it to store some information in extension's DB storage. So developers can make use of place holders which are replaced with original values after updating the resource.

Format for the templated string with placeholder - {{PLACEHOLDER}}

Supported Placeholders are,

  • ticket.id
  • thread.id

extra.key

Value for the key property is a string which can be a template key. Key for which the given value has to be stored in the DB storage.

For Example,

When a like count of a post has to be stored in the extension's db storage so that an app can re-access them, the external resource response's extra.key can be specified as
facebook_comment_{{thread.id}}_data.
When the external resource is processed and generated as a desk thread with threadId 2980928, the key will be replaced as facebook_comment_2980928_data and the value given in the extra.value will be stored for the key facebook_comment_2980928_data in that app's DB storage. Later the app can lookup the DB storage from the widget with the key facebook_comment_2980928_data to get the value of the likes count.

                    
PULL REQUEST FORMAT:
URL : channel.sync.pull RequestMethod : POST QueryParams : securityContext, orgId Content-Type : application/json RequestBody : All the non-secure configParams (CONFIG_PARAMS_OBJECT).
CONFIG_PARAMS_OBJECT: { "channelState" : "{\"my_last_fetch_time\":\"Jan 11\"}", "myConfigParam1" : "My value for configParam", "myConfigParam2" : "My value for configParam2", "myConfigParam3" : "My value for configParam3" } PULL REQUEST RESPONSE FORMAT:
ResponseCode : 200 Content-Type : application/json Response : Updated Data to be added in desk in the #SYNC_RESPONSE_OBJECT format.

Pull Request from Desk

Desk periodically invokes a request to the endpoint specified in the
extension manifest's channel.sync.pull property. Pull requests are made every 4 minutes from the desk. You can send the new/ updated data of tickets and threads that needs to be updated in desk in the specified #SYNC_RESPONSE_OBJECT format.

*Tip : You might need to call the external service's API to get new data which has to be sent to the desk. Call the external service's API through Desk Invoke API so that authentications are handled automatically (e.g Using connections) .

*Tip : You might want to keep track of the syncing status of the data you transferred (e.g number of tickets remaining to be sync). Make use of channelState property, to store the tracking data during pull, push & import requests.

                    
PUSH REQUEST FORMAT:
URL : channel.sync.push RequestMethod : POST QueryParams : securityContext, orgId Content-Type : application/json RequestBody : JSONObject containing reply & configParams in #PUSH_REPLY_PAYLOAD_FORMAT format.
PUSH REQUEST RESPONSE FORMAT:
ResponseCode : 200 Content-Type : application/json Response : Data to be updated in desk in #PUSH_REPLY_RESPONSE_OBJECT format.

Push Reply from Desk

When an agent replies from the desk for a ticket or thread created by channel integration, the reply is pushed to the Resources.channel.sync.push endpoint of the app which needs to be delivered to the external service so that the reply will be processed further. The push endpoint given in the manifest is responsible for handling the desk reply, delivering it to the external service and submit the status & response of the processed reply to the desk back.
The Progress of an agent reply from the desk for a ticket or thread created via channel integration are,

  • Agent reply is added in the desk with status PENDING.
  • Reply is pushed to the push_endpoint of the app.

*Tip : To send the received agent reply to other service, you may need to call other service's APIs. Use Desk Invoke API to call the external service's API, so that authentications are handled automatically (e.g Using connections) .

                    
Sample of #PUSH_REPLY_PAYLOAD_FORMAT:
{ "configParams" :{ "channelState" : "{\"my_last_fetch_time\":\"Jan 11\"}", "myConfigParam1" : "My value for configParam", "myConfigParam2" : "My value for configParam2", "myConfigParam3" : "My value for configParam3" }, "resource":{ "extParentId" : "1276576533", "replyToExtId" : "3298dniuniu3", "id" : 287189379819, "content" : "Hi customer, thanks for writing to us", "summary" : "Hi customer, thanks for writing to us", "contentType" : "text/plain", "hasAttach" : false, "attachments" : [], "author" : { "name" : "John Snow", "email" : "john.snow@example.com", "type" : "AGENT", "photoURL" : "https://desk.zoho.com/api/v1/agents/387829/photo?orgId=28732" } } }

#PUSH_REPLY_PAYLOAD_FORMAT

FieldTypeDescription
configParams JSONObject CONFIG_PARAMS_OBJECT All the non-secure config params belongs to the app.
resource JSONObject DESK_REPLY_THREAD_OBJECT Details of the Agent's reply to be sent to the external service.

#DESK_REPLY_THREAD_OBJECT

FieldTypeDescription
extParentId string External Id of the thread's ticket. (i.e) Parent Entity's ID of the thread in the external service.
replyToExtId string Add the reply to this message in the External Service. External Id of the thread to which the reply has to be added.
id long ID of the thread.
author JSONObject Details about the author with the following properties.
  • name
  • email
  • type
  • photoURL
content string Content of the thread.
contentType string Content-Type of the content of the thread. Possible Values are
  • text/plain
  • text/html
summary string Summary of the thread.
hasAttach boolean Specifies whether thread has attachments.
attachments JSONArray <JSONObject> Attachments in the thread. Each attachment object contains properties:
  • id
  • name
  • size
  • href
attachmentCount integer Count of the attachments
createdTime Timestamp ISO Format URL to get the full content of the thread.

#PUSH_REPLY_RESPONSE_OBJECT

FieldRequiredTypeDescription
extId yes string Unique ID of the thread added in the external service.
extra JSONObject #SYNC_EXTRA_OBJECT Extra information about the thread for the extension.
canReply boolean Specifies whether replies can be added to this thread.
from string From address of the thread.
Default : Channel Name
to JSONArray <string> Direct Recipients of the thread

Push-Data to Desk

                    
PUSH REQUEST FORMAT:
API Endpoint : /api/v1/channels/{{installationId}}/import RequestMethod : POST Content-Type : application/json RequestBody : JSONObject in the #SYNC_RESPONSE_OBJECT format.

Whenever you need to manually push tickets & threads to the desk, you can use the following API. This API expects the payload in the #SYNC_RESPONSE_OBJECT format.

To call desk's "channels/import" API, orgId and securityContext params are mandatory. You may obtain these details during any of the extension event callbacks & store them so that you can reuse them during the channels/import API call.

*Tip : Call the channels/import API through Desk Invoke API so that authentications are handled automatically (e.g Using connections) .

For Example:

You may have subscribed to the events such as onConfigParamAdd, onDeskAuthorize or onTPAAuthorise in the manifest's callBacks. Which will make request to the callback URL mentioned in the manifest with the securityContext & orgId during the respective events. During this event, you may subscribe to another service. The given orgId, securityContext can be stored or can be added in the subscription URL (e.g queryParams ) so that whenever the external service requests you with respect to the subscription, you can obtain the orgId and the securityContext from the URL and use it to call the desk "channels/import" API.

Channel State

About

Channel State represents the channelState non-secure configParam which is automatically added for the channel type of marketplace apps during installation. Channel State can be used as the current status of the channel's syncing process such as last fetched item, remaining API limit in the external service, pending or next set of entities to be fetched and so on.

The value of the channelState param can be any string which will be updated in the app's channelState configParam during the pull & push requests. If you don't want to update the channelState of the app in ZohoDesk, then exclude the channelState key while sending the sync request response.



                    
Source Redirection:
URL : channel.redirectUrl RequestMethod : GET QueryParams : entity, id, parentId

Source Redirection

The redirectUrl endpoint specified in the Manifest's channel param is responsible for redirecting the user to the external resource of an entity when requested by the desk.

Source Redirection Query Params

FieldDescription
entity Type of the entity to be redirected.
Supported Values are
  • ticket
  • thread
  • user_profile
id External Id of the entity in the external service.
parentId External Parent Id of the entity. In case of threads, parentId contains the extId of the ticket.

For example:

When an agent views a ticket, a hyperlink to the external resource will be shown to the agent. On clicking the hyperlink, the agent is redirected the redirectUrl in the manifest with the extId of the resource and the type of the entity as queryParams of the Url. The redirect URL should parse the entity type and id of the resource and redirect the user to the external service which contains the resource.

Extension Custom Actions

Introduction

How to use Custom Actions

How to create Custom Action

Configurations

Custom Permissions

Introduction

                

resources.json

... { "permissions": [{ "apiName": "createResolution", "displayName": "create Resolution test", "description": "Able to create the task", "defaultState": true }] }, ...

Custom permissions are new profile permissions that you can provide in the extension you develop. These permissions will be displayed under the PERMISSIONS tab on the extension detail page. Only the admins of a Zoho Desk portal will be able to configure these permissions.

How to define the custom permissions for the extension?
An extension developer can specify the Permissions details in resources.json file.

How does it work?
Custom permissions will be added when an admin installs the extension and deleted when they uninstall the extension. The permissions are specific to each installation of an extension. Therefore, admins can configure different permissions for an extension by installing it multiple times.

Admin configuration Permission Tab:

You can fetch the details of custom permissions in two ways:
1. Through the My Custom Permissions API within the extension, or
2. Through the My Custom Permissions REST API.



#CUSTOM_PERMISSION_FIELDS

FieldRequiredTypeDescription
apiName yes string apiName is the unique name given to each permission.apiName should be unique across each extension.apiName can have AlphaNumeric and underscore.
displayName yes string Name of the custom permission.This name will be displayed in "PERMISSIONS" tab.AlphaNumeric Values are allowed here.
description no string Description of the custom permission.
defaultState yes string Default state of custom permission. It can have boolean value. Either true or false(Case sensitive).