Zendesk Apps tutorial - Sending data to an external application

This tutorial shows you how to send data to a web app or service. You'll learn the following:

For the hands-on portion, you'll build a small app that creates tasks in Asana, a popular task management application. A free account is available.

To get data from an external application, see Zendesk Apps tutorial - Getting data from an external application. With a basic knowledge of two-way interactions, you can integrate many web services in your organization's support workflow.

The tutorial assumes you have the Zendesk Apps Tools (ZAT), a collection of development tools for building apps rapidly. See Installing and using the Zendesk Apps Tools.

Disclaimer: Zendesk provides this article for instructional purposes only. The Zendesk Support team does not provide support for the content. Please post any issue in the comments section below or in the Zendesk Apps community, or search for a solution online for issues with third-party technologies like Handlebars.

Core concepts

Zendesk apps send data to remote servers by making HTTP PUT or POST requests. If the app makes requests to a public API that doesn't require authentication or any other sensitive information, you can use jQuery.ajax() or the standard XMLHttpRequest JavaScript API.

When making requests from an app installed in Zendesk Support, the request settings can be viewed in the browser console by agents. Some settings may contain sensitive information such as an API access token. Example:

You can hide the information from agents by using the framework's client.request() method and storing the information in Zendesk Support with an app installation setting. Zendesk Support then inserts the information in the request server-side in the proxy layer, bypassing the browser.

Creating a secure request is a four-step process. First, you configure the request. Second, you secure any sensitive settings. Third, you send the request. Fourth, you wait for the request's outcome and handle its success or failure.

You'll also need to get the data from the support agent with an HTML form.

Configure the request

You specify the settings of a request in a JavaScript object. Example:

var settings = {  url: 'https://www.example.com/api/v2/leads.json',  headers: {"Authorization": "Bearer PyOAYC3N62gqpf"},  type: 'POST',  contentType: 'application/json',  data: JSON.stringify({lead: {name: 'Jay Gatsby', email: '[email protected]'}})};...

The settings object doesn't actually make the request; it just configures it. The example specifies the 5 properties necessary to complete this particular request:

  • url specifies the URL of the resource to process your data and create a record
  • headers specifies HTTP headers, in this case an authorization header to authenticate the request. You can secure the information in the headers before deploying the app, as explained in the step 2 below
  • type specifies the type of request to make, such as PUT or POST. Generally, POST requests create records while PUT requests update records
  • contentType specifies the type of data you're sending. If the server expects XML instead of JSON, use contentType: 'application/xml'
  • data is the data payload you're sending to the server. Make sure to structure the data according to the requirements of the API endpoint. If your data consists of a JavaScript object and the server expects JSON, stringify the data with the JSON.stringify() function. If the server expects XML, send the XML as a string, such as:

    data: '<lead><name>Jay Gatsby</name><email>[email protected]</email></lead>'

The settings may vary depending on the request. They include many of the same options as jQuery.ajax() requests. For details, see the jQuery documentation.

Step 2: Secure sensitive information

You should secure any sensitive information in your request settings before deploying the app.

You can store the information in Zendesk Support and Zendesk Support will insert it in your requests on the server side, bypassing the browser on the client side.

You store settings in Zendesk Support by specifying them as installation settings. Not to be confused with request settings, these are the settings a Zendesk Support admin is prompted to enter when installing the app.

You don't need to perform this task until you're ready to deploy the app for the first time. You can build and test your app locally with sensitive information in your code because you're the only one making the requests. Securing the information should be the last step before uploading the app for others to use for the first time.

To secure senstive information

  1. Create an installation setting in the manifest.json file as follows:

    ..."parameters": [  {    "name": "token",    "type": "text",    "secure": true,    "required": true  }],...

    This adds a required field labeled token on the app's installation page in Zendesk Support. The admin must enter a token before the app can be installed.

  2. Allow the resource's domain name by specifying a "domainWhitelist" property:

    "domainWhitelist": ["example.com"],...

    Specify only the domain name or names in the array. Don't include "https://".

  3. In your request settings, replace the sensitive information with a {{setting.name}} placeholder, and add a secure: true property. Example:

    var settings = {  url: 'https://www.example.com/api/v2/leads.json',  headers: {"Authorization": "Bearer {{setting.token}}"},  secure: true,  type: 'POST',  contentType: 'application/json',  data: JSON.stringify({lead: {name: 'Jay Gatsby', email: '[email protected]'}})};

At this point you'd normally upload and install the app in Zendesk Support. You'll be prompted to enter the secure information during the installation process. Example:

After installing the app, you can still make and test changes in the app installed in Zendesk Support. See Testing a Zendesk app that uses app requirements or secure requests.

Make the request

Make secure requests using the request() method of the ZAFClient object. Use the ZAFClient.init() method to create the client, then call the request() method with your request settings:

var client = ZAFClient.init();client.request(settings).then(...);

Verify the outcome of the request

Check for confirmation from the server that the request was successful. A request can fail for a number of reasons, including a network problem or a problem in your code.

Handle the outcomes with callback functions. Callbacks are executed only when a request is finished. For example, you can tell your app to run one function if the completed request was successful, and run another function if the request was not.

Specify the callbacks as arguments of the then() method of the Promise returned by the request. The then() method is called only when the request is finished.

The method takes two arguments: a function to run on success and a function to run on failure. Example:

client.request(settings).then(  function(data) {    showInfo(data);  },  function(response) {    showError(response);  });

If the request in the example succeeds, the response body is passed to the showInfo() function, which is then executed.

Try it: Build a data-entry app

In this section you'll build a small app that creates tasks in Asana, a popular task management web application. Asana has the advantage of being easy to set up and use. If you're not an Asana user, you can sign up for the free account.

Let's say you use Asana to list and assign tech notes that your support team needs to write. You decide to build an app that lets agents add tech note ideas to the list from the Zendesk Support agent interface.

Note: To retrieve the tasks from Asana and display them in the agent interface, see Zendesk Apps tutorial - Getting data from an external application.

The completed app looks like this:

Here are the steps for building this app:

Before you start, make sure you have the latest version of the Zendesk Apps Tools (ZAT). See Installing and using the Zendesk Apps Tools.

Create an Asana project and add a few tasks

If you don't already have an Asana account, you can sign up for free. If you have an account, skip to step 4.

  1. Go to https://asana.com/ and sign up using Google, or enter your email address and click Get Started for Free.
  2. If not using Google, complete your profile by entering your name and a password.
  3. Enter team members if you like (optional), then enter "Support Team" as your team name. You can share tasks with members of the team.

  4. Create a project by clicking the Plus (+) icon next to the Projects label on the left side and create a new project named "Tech Notes".
  5. On the Tech Notes project page, click Add Task and enter a sample task to write a tech note on some subject. Example: "Clarify the serial number location".

You're done. For Asana basics, see the Fundamentals guide on the Asana site.

Get a personal access token

You'll need a personal access token from Asana to make API calls from your app.

  1. After signing in to Asana, click your user icon on the top-right side and select My Profile Settings.
  2. In the My Profile Settings dialog box, click Manage Developer Apps.
  3. Under the Personal Access Tokens heading, click the Create New Personal Access Token link.
  4. Enter a brief description for the token such as "ZAF v2 tutorials" and click Create.
  5. Save the token someplace safe. It won't be displayed again.

    If you lose it, return to this page to deauthorize it and create a new one.

Create the files for the app

  1. If not already done, create a folder called "tutorial_apps" somewhere on your hard drive.
  2. Open your command-line interface (the command prompt in Windows or Terminal on the Mac) and navigate to the "tutorial_apps" folder.
  3. Run the following command at the prompt:

    $ zat new
  4. When prompted, enter the following information:

    • author's name - your name
    • author's email - your email
    • author's url - your website url if you have one, or press Enter to leave it blank
    • app name - Send Data Tutorial v2
    • iFrame URI - press Enter to leave it blank. You'll use the default iframe file created by ZAT
    • directory name - data_send_v2

After you're done, the tool creates files for a new app. The window should look as follows in Mac OS X:

The tool also records properties about the app in the manifest.json file, including the host application (Zendesk Support), the app's location in the host (ticket sidebar), and the path to the file to be iframed in the host (assets/iframe.html). Example:

"location": {   "zendesk": {     "ticket_sidebar": "assets/iframe.html"   }},...

Adapt the files to your project

For the tutorial, you'll make the following changes to the default files to adapt them to your project:

  • Import the third-party libraries you'll need
  • Add a content placeholder in the HTML for your templates
  • Keep your JavaScript separate from your HTML

Tip: You can save and reuse these files in other projects, or create your own set of reusable files.

Import libraries

A Zendesk app consists of dynamic content displayed in an iframe in the host application. You can write everything from scratch yourself but it's much easier to use existing libraries.

In this tutorial, you'll use a bit of jQuery in your JavaScript, Handlbars as your templating engine, and Bootstrap CSS for styling.

  1. In a text editor, open the assets/iframe.html file.
  2. Link to the Bootstrap CSS by replacing the Zendesk Garden CSS in <head> tag with the following link tag:

    <link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
  3. Import the jQuery and Handlebars libaries by adding the following <script> tags after the <h2> tag in the body:

    ...<script src="https://cdn.jsdelivr.net/jquery/3.0.0/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>

    You can import the libraries from whatever source you like.

Add a content placeholder

In Handlebars, you insert the HTML generated by a template at runtime into an element in the DOM. You decide to use a div tag in the body to insert your template content.

  • Replace the <h2> heading, "Zendesk Apps Tools Iframe Scaffold", which you don't need, with the following div tag:

    <div id="content"></div>
Keep your JavaScript separate

It's best practice to keep your JavaScript separate from your HTML.

  1. Replace the following <script> tag:

    <script>// Initialise the Zendesk JavaScript API client// https://developer.zendesk.com/apps/docs/agent/zaf_v2var client = ZAFClient.init();client.invoke('resize', { width: '100%', height: '400px' });</script>

    with the following tag:

    <script type="text/javascript" src="main.js"></script>

    You'll move the JavaScript to the new main.js file below.

    Make sure the tag is after all the other script tags to ensure the imported libraries are loaded in memory before the browser reaches your script.

  2. Create a file named main.js file in the assets folder.
  3. In main.js, add the following function, which contains the JavaScript code you deleted from iframe.html above:

    $(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });});

    This jQuery statement defines a self-invoking, anonymous function that runs after iframe.html has finished loading in the browser.

  4. Save both files.

The iframe.html file should look like this:

<html><head>  <link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"></head><body>  <div id="content"></div>
  <script src="https://cdn.jsdelivr.net/jquery/3.0.0/jquery.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>  <script type="text/javascript" src="https://assets.zendesk.com/apps/sdk/2.0/zaf_sdk.js"></script>  <script type="text/javascript" src="main.js"></script></body></html>

The main.js file should look like this:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });});

Create a new task form

When the app starts, you want to show a form that agents can use to enter new tech note ideas. The form should let them specify a name for the task. It should also let them enter some optional notes about the task if they like.

For the tutorial, you'll create tasks in the "Tech Notes" project you created in Asana. To keep things simple, you'll specify the project id in a hidden form field. In a real app, you might create a dropdown menu and let the agent enter tasks in different projects.

You'll include the form in a template to give yourself the flexibility to enhance the app later with more views. In Handlebars, you create templates by including the markup in <script> tags in the main HTML file.

Note: You can also precompile templates, but that's beyond the scope of this tutorial. For more information, see How to Precompile Handlebars Templates.

  1. In your iframe.html file, add the following <script> tag before all the other <script> tags:

    <script id="add_task-hdbs" type="text/x-handlebars-template">  <form id="task-form">    <label for="name">Task name</label>    <input type="text" name="name" id="name" maxlength="50" placeholder="50 characters or less" />    <label for="notes">Notes</label>    <textarea name="notes" id="notes" placeholder="optional" />    <input type="hidden" name="project-id" id="project-id" value="{project_id}" />    <button id="add-btn" class="btn btn-primary btn-small">Add Task</button>  </form></script>

    The template consists of a form with textboxes for the task's name and optional notes. The button is styled with a Bootstrap button class.

  2. Replace the {project_id} placeholder value in the project-id hidden field with your Tech Notes project id in Asana.

    To get the id, make sure you're signed into Asana. In another tab in the same browser, enter the following url in the browser's address bar and press Enter:


    Your projects and their ids should appear in the browser window. Grab the id for "Tech Notes".

    If it didn't work, use the following cURL command in your command-line interface. See this article to learn more about cURL.

    curl https://app.asana.com/api/1.0/projects \  -H "Authorization: Bearer <personal_access_token>"
  3. Style some of the form elements by creating a file named main.css file in your assets folder and adding the following rules:

    body {  font-size: 13px;}
    label {  padding-top: 8px;}
    #name, #notes {  width: 95%;}
    #notes {  height: 5em;}
    button {  margin-top: 8px;  margin-bottom: 12px;}

    You can come back later and tweak the rules.

  4. Link to your new css stylesheet in iframe.html after the Bootstrap CSS link in the <head> tag:

    <head>  <link href="https://cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">  <link href="main.css" rel="stylesheet"></head>
  5. Save iframe.html and main.css.

Show the form on start-up

You want to show the form to agents as soon as the app starts.

  1. Switch to main.js and add the following showForm() function definition to the file:

    function showForm() {  var source = $("#add_task-hdbs").html();  var template = Handlebars.compile(source);  var html = template();  $("#content").html(html);}

    This function generates and inserts the HTML from the add_task-hdbs template into your iframe.html file at runtime. The first line references the <script> tag with an id of add_task-hdbs, which contains the template. The second line compiles the template. The third line generates the final HTML. The final line sets the HTML content of the <div> tag with an id of content.

  2. Add a call to the showForm() function in the self-invoking function at the top of the file:

    $(function() {  ...  showForm();});

    When the HTML file has finished loading in the browser, the anonymous function runs the showForm() function, which displays the content in the user interface.

  3. Save both files.

At this point, your main.js file should look like this:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });  showForm();});
function showForm() {  var source = $("#add_task-hdbs").html();  var template = Handlebars.compile(source);  var html = template();  $("#content").html(html);}

Handle the form's button click event

Add an event handler to react to a user clicking the form's Add Task button. The handler should validate the form, gather the form data, then call a function to make the POST request.

  • Add the following jQuery event handler after the showForm() call in the anonymous function at the top of the main.js file:

    ...$("#add-btn").click(function(event) {  event.preventDefault();  if ($("#name").val().length == 0) {    client.invoke('notify', 'Name can\'t be blank.', 'error');  } else {    var task = {      data: {        name: $("#name").val(),        notes: $("#notes").val(),        projects: [parseInt($("#project-id").val())]      }    };    sendTaskData(task, client);  }});

    After an agent clicks the form's Add Task button, the event handler blocks the form's default submit action. The event.preventDefault() method is necessary because the app uses JavaScript instead of HTML to submit the values.

    Next, the handler performs basic validation. You want to make sure the task name isn't blank before sending the data. The handler gets the form element with the name id (#name), then checks to see if its value is blank. If it's blank, it uses the framework's notify method to display a notification alerting the agent.

    If the value checks out, the handler assigns the form data to an object named task. The object's structure and properties must match the structure and properties expected by the API. Asana expects an object named data containing properties of the new task.

    Finally, the handler calls the sendTaskData() function. As well as the task object, it passes the client variable to the function because the function needs it to make the HTTP request. You'll define the function next.

    Note: The event handler is defined inside the anonymous function rather than outside of it because the form button doesn't exist in the DOM until the form is inserted by showForm().

Define the request

You can use the following Asana endpoint to create the tasks:

`POST  https://app.asana.com/api/1.0/tasks'

See the Asana docs for learn more about the endpoint.

  1. Add the following function definition to main.js:

    function sendTaskData(task, client) {  var settings = {    url: 'https://app.asana.com/api/1.0/tasks',    headers: {"Authorization": "Bearer your_personal_access_token"},    type: 'POST',    contentType: 'application/json',    data: JSON.stringify(task)  };  // make request}

    The settings object contains all the properties necessary to complete the API request based on the Asana's Create a Task doc. The data property specifies the task object you defined above, converted to JSON with JSON.stringify().

  2. Replace the your_personal_access_token placeholder in the request settings with the personal access token you created earlier. See Get your personal access token above.

Make the request

  1. Replace the // make request comment in sendTaskData() with the following client.request() method call:

    client.request(settings).then(  function() {    client.invoke('notify', 'Task successfully added to Asana.');    $('#task-form')[0].reset();  },  function(response) {    var msg = 'Error ' + response.status + ' ' + response.statusText;    client.invoke('notify', msg, 'error');  });client.invoke('notify', 'Task sent! Please wait...');

    If the request is successful, the first callback function is executed. If not, the second one is executed.

    The last line notifies the user that the task data was sent. Because the request is asynchronous, the app displays this message without waiting for a response from the server.

    On receiving a successful response, the app displays a notification that the task was added to Asana and resets the form. On receiving an error, the app builds an error message from the response data and uses it in a notification.

  2. Save the main.js file.

At this point, the main.js file should look like this:

$(function() {  var client = ZAFClient.init();  client.invoke('resize', { width: '100%', height: '400px' });  showForm();
  $("#add-btn").click(function(event) {    event.preventDefault();    if ($("#name").val().length == 0) {      client.invoke('notify', 'Name can\'t be blank.', 'error');    } else {      var task = {        data: {          name: $("#name").val(),          notes: $("#notes").val(),          projects: [parseInt($("#project-id").val())]        }      };      sendTaskData(task, client);    }  });
function showForm() {  var source = $("#add_task-hdbs").html();  var template = Handlebars.compile(source);  var html = template();  $("#content").html(html);}
function sendTaskData(task, client) {  var settings = {    url: 'https://app.asana.com/api/1.0/tasks',    headers: {"Authorization": "Bearer 0/266ed62fce7ab63043c8ba20a90be6da"},    type: 'POST',    contentType: 'application/json',    data: JSON.stringify(task)  };  client.request(settings).then(    function() {      client.invoke('notify', 'Task successfully added to Asana.');      $('#task-form')[0].reset();    },    function(response) {      var msg = 'Error ' + response.status + ' ' + response.statusText;      client.invoke('notify', msg, 'error');    }  );  client.invoke('notify', 'Task sent! Please wait...');}

Test and update the app locally

  1. In the command-line interface, navigate to your data_send_v2 folder.
  2. Start the local HTTP server with the following command at the prompt:

    $ zat server

    Note: If you get an error, make sure you navigate to your app's folder using the command line.

    After a moment, a status message appears informing you that the server has started.

    Note: The command prompt is unavailable until you shut down the server later.
  3. In a web browser, navigate to any ticket in Zendesk Support. The URL should look something like this:


  4. Append ?zat=true to the ticket URL, and reload the page.

    The URL should look like this:


  5. In your browser's Address bar, click the shield icon on the left (Chrome) or lock icon on the right (Firefox) and agree to load an unsafe script (Chrome) or to disable protection (Firefox). If you don't do this, the browser will block your app.

    Note: Safari has no option to disable protection. You must use Chrome or Firefox.

    The browser should reload the page and display the app start page (such as it is) in the ticket sidebar.

  6. In the app interface, enter the name of a task and some notes about it. After clicking Add Task, keep an eye on the upper-right side of the agent interface. A notification should appear telling you the task data was sent, followed after a moment by a success or error message. If all went well, the notification tells you that a task has been successfully created.
  7. Verify that the record was created by visiting your Asana page.
  8. If you like, continue enhancing the app and testing your changes.

    For example, you could add a dropdown menu of Asana projects and create tasks in other projects.

  9. When you're done, switch back to your command-line interface and press Control+C to shut down the local server.

Secure sensitive information

Before uploading and installing the app in Zendesk Support, make sure to secure any sensitive information that you don't want agents to see in the browser console. In this case, you don't want your authentication information to be visible.

Note: After securing the information, you'll no longer be able to test the app locally with the ZAT server. However, you'll still be able to test and update the app after installing it. We'll cover how in Test and update the app after installing it below.
  1. In the manifest.json file, add a parameters property to create an installation setting, as follows:

    ..."parameters": [  {    "name": "token",    "type": "text",    "secure": true,    "required": true  }],...

    The admin will have to enter a value for token before the app can be installed.

  2. Add a "domainWhitelist" property to allow the resource's domain name:

    "domainWhitelist": ["app.asana.com"],...

    Specify only the domain name. Don't include "https://".

  3. In your request settings in main.js, replace the actual token with the {{setting.token}} placeholder, then add a secure: true property. Example:

    var settings = {  url: 'https://app.asana.com/api/1.0/tasks',  headers: {"Authorization": "Bearer {{setting.token}}"},  secure: true,  type: 'POST',  contentType: 'application/json',  data: JSON.stringify(task)};
  4. Save the files.

The completed manifest.json file should look as follows:

{  "name": "Send Data Tutorial v2",  "author": {    "name": "Charles Nadeau",    "email": "[email protected]",    "url": ""  },  "defaultLocale": "en",  "private": true,  "location": { "zendesk":    { "ticket_sidebar": "assets/iframe.html" }  },  "domainWhitelist": ["app.asana.com"],  "parameters": [     {       "name": "token",       "type": "text",       "secure": true,       "required": true     }   ],  "version": "1.0",  "frameworkVersion": "2.0"}

Upload and install the app

  1. Validate your files:

    $ zat validate

    Fix any problems reported by the tool, then run zat validate again.

  2. Package your files for upload:

    $ zat package
  3. Upload and install the app as a private app in your Zendesk Support instance. For instructions, see Uploading and installing your private app in Zendesk Support.
  4. During the install process, paste your Asasa personal access token in the token field:

After you're done, you can view and test the app in the agent interface. If you need to debug or make additional changes, you can make updates to the installed app as described in the next section.

Test and update the app after installing it

After securing your sensitive information, you can no longer test the app locally with the ZAT server. However, you can still test and update the app after installing it as described in this section.

  1. Make sure you're signed in to Zendesk Support, then paste the following URL in the browser's Address bar, replace your\subdomain_ in the URL with your own, and press Enter:


    You should see a JSON object listing all the apps installed in Zendesk Support.

  2. Find your app and copy the app_id.
  3. Create a file named .zat in the local root directory of your app.

    Creating files with a leading period can be problematic in both Mac OSX and Windows.

    On a Mac, you can run the following command in the app's root directory:

    $ touch .zat

    In Windows, create the file in NotePad with File > Save As.

  4. Add the following JSON object to the file:

    {  "subdomain": "your_subdomain",  "username": "your_username",  "app_id": 0000}

    Replace the property values with your own values. The username is your Zendesk Support account username, which is always an email address.

  5. Make changes to your app.
  6. Update the installed app with your changes by running the following command and entering your Zendesk Support account password.

    $ zat update
  7. In Zendesk Support, refresh the apps and test your app.
  8. If you like, continue enchancing the app and testing the changes. Some ideas:

    • Apply some CSS to make it look more professional. Remember that you have all of the Bootstrap CSS at your disposal, which you can customize with your own rules
    • Spruce up the splash page by adding your own logo. See Changing the logo in the getting started tutorial

Additional resources