Extension Incoming Webhook Handler

Extension Incoming Webhook Handler

Integration with external applications can be done with the help of incoming webhook APIs. An extension token or ZAPI key generated by each user interacting with the extension, should be used for handling incoming webhooks and messaging apis. You will get the below given list of attributes when the extension's incoming webhook handler is executed:


User Scenario

Let us consider an extension integrating GitLab and Cliq.  The installation validator authorizes the user to install the extension upon checking if they have an account in GitLab. The handler is triggered to activate the installed extension.  Following this installation and activation, the extension's webhook endpoints are configured by through a slash command. 

Note:
Configuring an extension's incoming webhook endpoint can be done through the following internal components - Slash Command, Bot, Message Action. 

Setting up webhooks in the GitLab for Cliq Extension

Create a slash command to configure webhooks for all your GitLab projects. Executing the command will return the token generation button as response. On clicking this button, each user will generate an extension token (ZAPI Key). The function associated with this button will register the webhooks for all GitLab projects present in your account. 

Slash command execution code

  1. response = Map();
  2. response = {"text":"Click on the token generation button below!","buttons":[
  3.   {
  4.     "label": "Create Webhook",
  5.     "type": "+",
  6.     "action": {
  7.       "type": "invoke.function",
  8.       "data": {
  9.         "name": "authenticate"
  10.       },
  11.      "confirm":{
  12.      "title":"Generate Webhooks for a GitLab Project",
  13.       "description":"Connect to GitLab Projects from within Cliq",
  14.        "input" : 
  15.          {"type":"user_webhook_token"
  16.                  }
  17.          }
  18.     }
  19.   }
  20.   ]};
  21. return response;

Button Function Code

  1. response = Map();
  2. info arguments;
  3. token = arguments.get("input").get("token");
  4. info token;
  5. git_projects = invokeurl
  6. [
  7.         url :"https://gitlab.com/api/v4/projects?visibility=private&simple=true%22
  8.         type :GET
  9.         connection:"ENTER YOUR CONNECTION NAME"
  10. ];
  11. info git_projects;
  12. for each  project in git_projects
  13. {
  14. info "here";
  15.         projectID = project.get("id");
  16.         info projectID;
  17.         paramsMap = Map();
  18.         paramsMap = {"url":"https://cliq.zoho.com/api/v2/applications/%22+APPID+%22/incoming?appkey=%22+APPKEY+%22&zapikey=%22 +token,"id":projectID,"push_events":true,"issues_events":true,"note_events":true,"merge_requests_events":true};
  19.         createWebhook = invokeurl
  20.         [
  21.                 url :"https://gitlab.com/api/v4/projects/%22 + projectID + "/hooks"
  22.                 type :POST
  23.                 parameters:paramsMap
  24.                 connection:"ENTER YOUR CONNECTION NAME"
  25.         ];
  26.         }
  27. info createWebhook;
  28. return response;

Extension Incoming Webhook Endpoint Workflow

The custom callbacks directed to the extension's incoming webhook endpoint should be handled in the extension's incoming webhook handler. The JSON response from the third party application will be passed as headers, parameters or in the body attribute. In this example, the response is available in the body parameter. The extension's webhook endpoint is called for any event update or change made in a GitLab project. According to the response received, a message is configured and posted to a channel of your choice. 

  1. info body;
  2. result = body.toMap();
  3. if(result.get("object_kind") == "issue" && result.get("object_attributes").get("action") == "open")
  4. {
  5.         name = body.get("user").get("name");
  6.         title = result.get("object_attributes").get("title");
  7.         project = result.get("project").get("name");
  8.         state = result.get("object_attributes").get("state");
  9.         repository = result.get("repository").get("name");
  10.         url = result.get("object_attributes").get("url");
  11.         if(result.get("object_attributes").get("due_date") == "null")
  12.         {
  13.                 duedate = "Null";
  14.         }
  15.         else
  16.         {
  17.                 duedate = result.get("object_attributes").get("due_date");
  18.                 dateandtime = duedate.toTime("yyyy-MM-dd HH:mm:ss","UTC");
  19.                 duedate = dateandtime.toString("dd-MMM-yyyy hh:mm a",user.get("timezone"));
  20.         }
  21.         if(result.containKey("assignees"))
  22.         {
  23.                 assignee = result.get("assignees").getJSON("name");
  24.                 info assignee;
  25.         }
  26.         else
  27.         {
  28.                 assignee = "No assignee";
  29.         }
  30.         response = {"text":"### :bug: Issue has been created by '" + name + "' in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nState: " + state + "\nProject: " + project + "\nAssignee: " + assignee + "\nDue date: " + duedate,"card":{"theme":"1"}};
  31. }
  32. else if(result.get("object_kind") == "issue" && result.get("object_attributes").get("action") == "reopen")
  33. {
  34.         name = body.get("user").get("name");
  35.         title = result.get("object_attributes").get("title");
  36.         project = result.get("project").get("name");
  37.         state = result.get("object_attributes").get("state");
  38.         repository = result.get("repository").get("name");
  39.         url = result.get("object_attributes").get("url");
  40.         if(result.get("object_attributes").get("due_date") == "null")
  41.         {
  42.                 duedate = "Null";
  43.         }
  44.         else
  45.         {
  46.                 duedate = result.get("object_attributes").get("due_date");
  47.                 dateandtime = duedate.toTime("yyyy-MM-dd HH:mm:ss","UTC");
  48.                 duedate = dateandtime.toString("dd-MMM-yyyy hh:mm a",user.get("timezone"));
  49.         }
  50.         if(result.containKey("assignees"))
  51.         {
  52.                 assignee = result.get("assignees").getJSON("name");
  53.                 info assignee;
  54.         }
  55.         else
  56.         {
  57.                 assignee = "No assignee";
  58.         }
  59.         response = {"text":"### :bug: Issue has been reopened by '" + name + "' in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nState: " + state + "\nProject: " + project + "\nAssignee: " + assignee + "\nDue date: " + duedate,"card":{"theme":"1"}};
  60. }
  61. else if(result.get("object_kind") == "issue" && result.get("object_attributes").get("action") == "update")
  62. {
  63.         name = body.get("user").get("name");
  64.         title = result.get("object_attributes").get("title");
  65.         project = result.get("project").get("name");
  66.         state = result.get("object_attributes").get("state");
  67.         repository = result.get("repository").get("name");
  68.         url = result.get("object_attributes").get("url");
  69.         if(result.get("object_attributes").get("due_date") == "null")
  70.         {
  71.                 duedate = "Null";
  72.         }
  73.         else
  74.         {
  75.                 duedate = result.get("object_attributes").get("due_date");
  76.                 dateandtime = duedate.toTime("yyyy-MM-dd HH:mm:ss","UTC");
  77.                 duedate = dateandtime.toString("dd-MMM-yyyy hh:mm a",user.get("timezone"));
  78.         }
  79.         if(result.containKey("assignees"))
  80.         {
  81.                 assignee = result.get("assignees").getJSON("name");
  82.                 info assignee;
  83.         }
  84.         else
  85.         {
  86.                 assignee = "No assignee";
  87.         }
  88.         response = {"text":"### :bug: Issue has been updated by '" + name + "' in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nState: " + state + "\nProject: " + project + "\nAssignee: " + assignee + "\nDue date: " + duedate,"card":{"theme":"1"}};
  89. }
  90. else if(result.get("object_kind") == "issue" && result.get("object_attributes").get("action") == "close")
  91. {
  92.         name = body.get("user").get("name");
  93.         title = result.get("object_attributes").get("title");
  94.         project = result.get("project").get("name");
  95.         state = result.get("object_attributes").get("state");
  96.         repository = result.get("repository").get("name");
  97.         url = result.get("object_attributes").get("url");
  98.         if(result.get("object_attributes").get("due_date") == "null")
  99.         {
  100.                 duedate = "Null";
  101.         }
  102.         else
  103.         {
  104.                 duedate = result.get("object_attributes").get("due_date");
  105.                 dateandtime = duedate.toTime("yyyy-MM-dd HH:mm:ss","UTC");
  106.                 duedate = dateandtime.toString("dd-MMM-yyyy hh:mm a",user.get("timezone"));
  107.         }
  108.         if(result.containKey("assignees"))
  109.         {
  110.                 assignee = result.get("assignees").getJSON("name");
  111.                 info assignee;
  112.         }
  113.         else
  114.         {
  115.                 assignee = "No assignee";
  116.         }
  117.         response = {"text":"### :bug: Issue has been closed by '" + name + "' in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nState: " + state + "\nProject: " + project + "\nAssignee: " + assignee + "\nDue date: " + duedate,"card":{"theme":"1"}};
  118. }
  119. else if(result.get("object_kind") == "push")
  120. {
  121.         username = result.get("user_name");
  122.         //name = result.get("commits").getJSON("author").get("name");
  123.         msg = result.get("commits").getJSON("message");
  124.         url = result.get("commits").getJSON("url");
  125.         repository = result.get("repository").get("name");
  126.         response = {"text":"*'" + username + "'* has made a commit  [" + msg + "](" + url + ")  in the repository *'" + repository + "'*","card":{"theme":"3","title":" Commit changes"}};
  127. }
  128. else if(result.get("object_kind") == "note")
  129. {
  130.         username = result.get("user").get("name");
  131.         //name = result.get("commits").getJSON("author").get("name");
  132.         msg = result.get("object_attributes").get("note");
  133.         url = result.get("object_attributes").get("url");
  134.         repository = result.get("repository").get("name");
  135.         commitname = result.get("commit").get("message");
  136.         response = {"text":"*'" + username + "'* has added a comment  [" + msg + "](" + url + ") for the commit *'" + commitname + "'* in the repository *'" + repository + "'*","card":{"theme":"3","title":":task: Comment Added for a Commit"}};
  137. }
  138. else if(result.get("object_kind") == "merge_request" && result.get("object_attributes").get("action") == "open")
  139. {
  140.         title = result.get("object_attributes").get("title");
  141.         project = result.get("project").get("name");
  142.         repository = result.get("repository").get("name");
  143.         url = result.get("object_attributes").get("url");
  144.         if(result.containKey("assignee"))
  145.         {
  146.                 assignee = result.get("assignee").get("name");
  147.                 info assignee;
  148.         }
  149.         else
  150.         {
  151.                 assignee = "No assignee";
  152.         }
  153.         sourcebranch = result.get("changes").get("source_branch").get("current");
  154.         targetbranch = result.get("changes").get("target_branch").get("current");
  155.         response = {"text":"### New merge request in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nSource branch: " + sourcebranch + "\nTarget branch: " + targetbranch + "\nAssignee: " + assignee,"card":{"theme":"1"}};
  156. }
  157. else if(result.get("object_kind") == "merge_request" && result.get("object_attributes").get("action") == "close")
  158. {
  159.         title = result.get("object_attributes").get("title");
  160.         //project = result.get("project").get("name");
  161.         repository = result.get("repository").get("name");
  162.         url = result.get("object_attributes").get("url");
  163.         if(result.containKey("assignee"))
  164.         {
  165.                 assignee = result.get("assignee").get("name");
  166.                 info assignee;
  167.         }
  168.         else
  169.         {
  170.                 assignee = "No assignee";
  171.         }
  172.         sourcebranch = result.get("object_attributes").get("source_branch");
  173.         targetbranch = result.get("object_attributes").get("target_branch");
  174.         response = {"text":"### Merge request has been closed in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nSource branch: " + sourcebranch + "\nTarget branch: " + targetbranch + "\nAssignee: " + assignee,"card":{"theme":"1"}};
  175. }
  176. else if(result.get("object_kind") == "merge_request" && result.get("object_attributes").get("action") == "reopen")
  177. {
  178.         title = result.get("object_attributes").get("title");
  179.         repository = result.get("repository").get("name");
  180.         url = result.get("object_attributes").get("url");
  181.         if(result.containKey("assignee"))
  182.         {
  183.                 assignee = result.get("assignee").get("name");
  184.                 info assignee;
  185.         }
  186.         else
  187.         {
  188.                 assignee = "No assignee";
  189.         }
  190.         sourcebranch = result.get("object_attributes").get("source_branch");
  191.         targetbranch = result.get("object_attributes").get("target_branch");
  192.         response = {"text":"### Merge request has been reopened in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nSource branch: " + sourcebranch + "\nTarget branch: " + targetbranch + "\nAssignee: " + assignee,"card":{"theme":"1"}};
  193. }
  194. else if(result.get("object_kind") == "merge_request" && result.get("object_attributes").get("action") == "update")
  195. {
  196.         title = result.get("object_attributes").get("title");
  197.         repository = result.get("repository").get("name");
  198.         url = result.get("object_attributes").get("url");
  199.         if(result.containKey("assignee"))
  200.         {
  201.                 assignee = result.get("assignee").get("name");
  202.                 info assignee;
  203.         }
  204.         else
  205.         {
  206.                 assignee = "No assignee";
  207.         }
  208.         sourcebranch = result.get("object_attributes").get("source_branch");
  209.         targetbranch = result.get("object_attributes").get("target_branch");
  210.         response = {"text":"### Merge request has been updated in the repository '" + repository + "' \n\n*Details are as follows:*\nTitle: [" + title + "](" + url + ") \nSource branch: " + sourcebranch + "\nTarget branch: " + targetbranch + "\nAssignee: " + assignee,"card":{"theme":"1"}};
  211. }
  212. zoho.cliq.postToChannel("ENTER CHANNEL UNIQUE NAME",response);
  213. return Map();




    Zoho CRM Training Programs

    Learn how to use the best tools for sales force automation and better customer engagement from Zoho's implementation specialists.

    Zoho CRM Training
      Redefine the way you work
      with Zoho Workplace

        Zoho DataPrep Personalized Demo

        If you'd like a personalized walk-through of our data preparation tool, please request a demo and we'll be happy to show you how to get the best out of Zoho DataPrep.

        Zoho CRM Training

          Create, share, and deliver

          beautiful slides from anywhere.

          Get Started Now


            Zoho Sign now offers specialized one-on-one training for both administrators and developers.

            BOOK A SESSION








                                You are currently viewing the help pages of Qntrl’s earlier version. Click here to view our latest version—Qntrl 3.0's help articles.




                                    Manage your brands on social media

                                      Zoho Desk Resources

                                      • Desk Community Learning Series


                                      • Digest


                                      • Functions


                                      • Meetups


                                      • Kbase


                                      • Resources


                                      • Glossary


                                      • Desk Marketplace


                                      • MVP Corner


                                      • Word of the Day


                                        Zoho Marketing Automation

                                          Zoho Sheet Resources

                                           

                                              Zoho Forms Resources


                                                Secure your business
                                                communication with Zoho Mail


                                                Mail on the move with
                                                Zoho Mail mobile application

                                                  Stay on top of your schedule
                                                  at all times


                                                  Carry your calendar with you
                                                  Anytime, anywhere




                                                        Zoho Sign Resources

                                                          Sign, Paperless!

                                                          Sign and send business documents on the go!

                                                          Get Started Now




                                                                  Zoho TeamInbox Resources



                                                                          Zoho DataPrep Resources



                                                                            Zoho DataPrep Demo

                                                                            Get a personalized demo or POC

                                                                            REGISTER NOW


                                                                              Design. Discuss. Deliver.

                                                                              Create visually engaging stories with Zoho Show.

                                                                              Get Started Now







                                                                                            You are currently viewing the help articles of Sprints 1.0. If you are a user of 2.0, please refer here.

                                                                                            You are currently viewing the help articles of Sprints 2.0. If you are a user of 1.0, please refer here.



                                                                                                  • Related Articles

                                                                                                  • Extension Installation Handler

                                                                                                    This handler is triggered after the installation of the extension. The main purpose of this handler is to let you (extension creator) handle certain processes, like configuring webhooks after a user installs the extension. Click Edit Code under ...
                                                                                                  • Extension Webhook

                                                                                                    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 ...
                                                                                                  • Extension Properties

                                                                                                    What are extension properties?  Extension properties are values associated with the extension. They are quite similar to regular data properties, wherein you map a key of type string with a value string.  The main purpose is to store data ...
                                                                                                  • Extension Token (ZAPI Key)

                                                                                                    The extension token, also known as ZAPI Key is an unique authentication key generated for each user who interacts with any component in the extension. This token can be used to connect your extension with a third party application through webhooks, ...
                                                                                                  • Extension Installation Validator

                                                                                                    The installation validator is triggered to validate the user before installing the extension. The validator is not configured by default. If the installation validator is not configured, users will be allowed to install the extension without ...
                                                                                                    Wherever you are is as good as
                                                                                                    your workplace

                                                                                                      Resources

                                                                                                      Videos

                                                                                                      Watch comprehensive videos on features and other important topics that will help you master Zoho CRM.



                                                                                                      eBooks

                                                                                                      Download free eBooks and access a range of topics to get deeper insight on successfully using Zoho CRM.



                                                                                                      Webinars

                                                                                                      Sign up for our webinars and learn the Zoho CRM basics, from customization to sales force automation and more.



                                                                                                      CRM Tips

                                                                                                      Make the most of Zoho CRM with these useful tips.



                                                                                                        Zoho Show Resources