This tutorial shows you how to build a simple ZIS integration from scratch. The integration will listen for Ticket Created events in Zendesk. When it detects the event, the integration will post the ticket's id, status, and priority to an external target representing an external application.

The tutorial consists of the following parts:

Disclaimer: Zendesk provides this article for instructional purposes only. The integration and examples are not meant for production environments. Zendesk also does not provide support for the test integration. Please post any issue in the Zendesk developer community or search for a solution online.

What you need

To build the example integration, you’ll need the following:

  1. A Zendesk account for testing. ZIS is supported on the Zendesk Suite Growth plan or above, and the Support Professional plan or above. If you don't have a Zendesk account for testing, you can get a free sponsored test account. See Request a sponsored test account. The test account supports ZIS.

  2. Be an admin on the account or have access to somebody who is an admin. The admin can give you admin access. See Setting roles and access in Zendesk Admin Center.

  3. An external target representing an external application. You can get a free target by visiting https://webhook.site/. The site automatically creates a unique target URL for you and echoes back any data you send to it.

    If you use the free version of webhook.site, the URL automatically expires in 7 days. You can get a new one.

Registering the integration name

The first step in building an integration is registering the name of the integration with the ZIS Registry Service. The name you choose has to be globally unique and can be up to 64 characters long. Only the following characters are allowed: lower-case letters (a-z), numbers, hyphens (-), and underscores (_).

Registering the name of the integration is done by making an API request to the Create Integration endpoint specifying a unique name for the integration.

To authenticate the request, you can use basic authentication with a Zendesk username and password or an API token. If you haven't done so already, check that API access is enabled in Admin Center under Apps and Integrations > APIs > Zendesk APIs. See Using the API dashboard.

This tutorial gives Postman and curl examples of the same request, but you can use whatever tool you like to make requests.

Using Postman

  1. In Postman, select File > New > HTTP Request.

  2. In the Postman request editor, enter the Create Integration endpoint:

    https://{subdomain}.zendesk.com/api/services/zis/registry/{integration_name}

    Replace {subdomain} with your Zendesk subdomain and {integration_name} with the name you'd like to register for your integration. Because it must be globally unique, use something specific to you, not "zis_tutorial".

  3. Select POST as the method on the left side.

  4. Click the Body tab below your request path. Make sure the raw and JSON options are selected and paste {"description": "An example integration"}.

  5. Click the Authorization tab, and under Type, select Basic Auth, and enter your Zendesk admin credentials.

  6. Click Send.

The request and response should look like this in Postman:

Don't confuse the identifier value in the response with the integration name you just registered (miso_integration_3212 in the example). ZIS adds a zis_ prefix to the identifier value, which is only used to get an OAuth token. Your integration name is the name you gave it in the API request, without the prefix.

Save your registered integration name. In the example, it would be miso_integration_3212, not zis_miso_integration_3212.

Using curl

  • In your command line interface, make the following curl request:

    curl https://{subdomain}.zendesk.com/api/services/zis/registry/{integration_name} \  -d '{"description": "An example integration"}' \  -H "Content-type: application/json" \  -u {email_address}:{password} -X POST

Building the integration

The logic of a ZIS integration is defined in a ZIS bundle. A ZIS bundle is a JSON object that contains the following types of nested objects:

  • Action objects, which define HTTP requests and other actions
  • Flow objects, which define different states of the integration. Each state specifies an action to run when the integration enters that state
  • JobSpec objects, which specify the flows to run when given events happen

In this part of the tutorial, you'll create a starter bundle and then populate it with the JSON objects that define the logic of your integration.

Creating a starter bundle

In this section, you’ll create an empty starter bundle with placeholders for the following objects that you'll add later:

  • an Action object to post the id, status, and priority of a ticket to an external target
  • a Flow object to run the action and pass the ticket's data to it
  • a JobSpec object to run the flow when a Ticket Created event is detected, and pass the new ticket's data to the flow

To create the starter bundle

  1. Create a JSON file named my_zis_bundle.json.

  2. Add the following bundle skeleton to the file:

    {  "name": "My first ZIS integration",  "description": "Posts ticket data to an external target on ticket create",  "zis_template_version": "2019-10-14",  "resources": {    "action_post_ticket_data": {      "_placeholder_": "ZIS Action properties here"    },    "flow_ticket_created": {      "_placeholder_": "ZIS Flow properties here"    },    "jobspec_handle_ticket_event": {      "_placeholder_": "ZIS JobSpec properties here"    }  }}

You'll define the action, flow, and job spec in the next sections.

Note: You shouldn't change the zis_template_version value.

For more information on ZIS bundles, see Anatomy of a ZIS bundle and the Bundles API.

Defining a ZIS action

For the integration, you want a ZIS action that can make HTTP requests. When a Ticket Created event is detected by the integration, it should make a POST request sending the ticket data to the external target simulating the external application. You can create that specific functionality by building a custom action. For more information, see ZIS custom actions.

Suppose the external target expects the new ticket id in a header named X-Zendesk-Ticket-Id and the ticket status and priority in a JSON object named data.

In curl, the POST request to the target might look as follows:

curl https://webhook.site/4e69e10f-18f5-4543-afbc-bd121f16064f \  -H "key: X-Zendesk-Ticket-Id" \  -H "value: 45326774" \  -d '{"data": {"status": "new", "priority": "high"}}' \  -H "Content-Type: application/json" \  -X POST

In this section, you'll define the same POST request as a ZIS action.

To define your ZIS action

In your my_zis_bundle.json file, replace the placeholder line in the action_post_ticket_data object with the following ZIS Action properties (lines 2 to 21 below):

"action_post_ticket_data": {  "type": "ZIS::Action::Http",  "properties": {    "name": "action_post_ticket_data",    "definition": {      "method": "POST",      "url": "{external_target_url}",      "headers": [        {          "key": "X-Zendesk-Ticket-Id",          "value.$": "$.ticketId"        }      ],      "requestBody": {        "data": {          "status.$": "$.ticketStatus",          "priority.$": "$.ticketPriority"        }      }    }  }},

Replace the {external_target_url} placeholder with the URL you obtained from https://webhook.site/. Example: "https://webhook.site/4e69e10f-18f5-4543-afbc-bd121f16064f".

You did the following in the ZIS action:

  • Named your action action_post_ticket_data. ZIS validation rules require that an action’s properties.name be the same as its top-level key (in this case, action_post_ticket_data)
  • Used the type property to specify the type of the action is "ZIS::Action::Http"
  • Used the definition object to define the HTTP request

You also used variables named $.ticketId, $.ticketStatus, and $.ticketPriority to provide data to the action.

To assign a variable to a property in a ZIS action, add a ".$" suffix to the property name. Example: "status.$": "$.ticketStatus". The suffix will be omitted when the data is sent to the target.

You'll define the variables in the flow in the next section. To give you a preview, the variables above are defined as follows in the flow:

"Parameters": {  "ticketId.$": "$.input.ticket_event.ticket.id",  "ticketStatus.$": "$.input.ticket_event.ticket.status",  "ticketPriority.$": "$.input.ticket_event.ticket.priority"}

The input data in the example is received from the Ticket Created event specified in the job spec. The input data is documented in the Ticket Created event in the Trigger Events reference docs. For example, "$.input.ticket_event.ticket.status" corresponds to "new" in the example in the doc.

All parameters in ZIS bundles use JSONPath semantics.

Defining a ZIS flow

Now that you've defined the ZIS action, you can add it to a ZIS flow. A ZIS flow defines one or more states for the integration. You can create different types of states but in this tutorial you’ll create a state of type "Action" that runs the action you defined.

The integration in this tutorial enters its first (and only) state when a Zendesk ticket is created. In this section, you'll create a state named "ZendeskTicketCreated" and add your action to it.

To define your ZIS flow

In your my_zis_bundle.json file, replace the placeholder line in the flow_ticket_created object with the following ZIS Flow properties (lines 2 to 20):

"flow_ticket_created": {  "type": "ZIS::Flow",  "properties": {    "name": "ticket-created-flow",    "definition": {      "StartAt": "ZendeskTicketCreated",      "States": {        "ZendeskTicketCreated": {          "Type": "Action",          "ActionName": "zis:{integration_name}:action:action_post_ticket_data",          "Parameters": {            "ticketId.$": "$.input.ticket_event.ticket.id",            "ticketStatus.$": "$.input.ticket_event.ticket.status",            "ticketPriority.$": "$.input.ticket_event.ticket.priority"          },          "End": true        }      }    }  }},

You did the following in your ZIS flow:

  • Named your flow ticket-created-flow
  • Used the (required) StartAt property to specify the first state to enter when the flow is triggered by an event
  • Defined a ZendeskTicketCreated state in the (required) States object
  • Used the ActionName property to tell ZIS what action to run when the integration enters the ZendeskTicketCreated state
  • Defined variables used in your action in the Parameters object. The input data is received from Ticket Created event specified in the job spec. See the Ticket Created event in the Trigger Events reference docs. For example, "$.input.ticket_event.ticket.id" corresponds to 35436 in the example in the docs.
  • Set End to true in the ZendeskTicketCreated state to tell ZIS to exit the flow after the action runs

Defining a ZIS job spec

A JobSpec works like an event handler. It specifies a flow to run when a given event is detected.

A job spec also passes event data to the flow in the background. The format of the data depends on the event and is documented in the ZIS Trigger Events reference docs.

The integration in this tutorial runs your ticket-created-flow flow when a ticket is created.

To define your ZIS job spec

In your my_zis_bundle.json file, replace the placeholder line in the jobspec_handle_ticket_event object with the following ZIS JobSpec properties (lines 2 to 9):

"jobspec_handle_ticket_event": {  "type": "ZIS::JobSpec",  "properties": {    "name": "handle-ticket-created-event",    "event_source": "support",    "event_type": "ticket.TicketCreated",    "flow_name": "zis:{integration_name}:flow:ticket-created-flow"  }}

You did the following in your ZIS job spec:

  • Used the event_source property to tell ZIS that the source of the event is support. See Referencing an event in a JobSpec in the reference docs.

  • Used the event_type property to tell ZIS to listen for the "ticket.TicketCreated" event. The event will pass data to your flow in the background. For an example of the data passed to the flow, see the Ticket Created doc.

  • Used the flow_name property to tell ZIS to run your ticket-created-flow flow when it detects the Ticket Created event. The flow_name property uses the following format for the value: zis:{integration_name}:flow:{flow_name}.

Code complete

Your action, flow, and job spec now make up a complete ZIS bundle. Your my_zis_bundle.json file should look as follows:

{  "name": "My first ZIS integration",  "description": "Posts ticket data to an external target on ticket create",  "zis_template_version": "2019-10-14",  "resources": {    "action_post_ticket_data": {      "type": "ZIS::Action::Http",      "properties": {        "name": "action_post_ticket_data",        "definition": {          "method": "POST",          "url": "{external_target_url}",          "headers": [            {              "key": "X-Zendesk-Ticket-Id",              "value.$": "$.ticketId"            }          ],          "requestBody": {            "data": {              "status.$": "$.ticketStatus",              "priority.$": "$.ticketPriority"            }          }        }      }    },    "flow_ticket_created": {      "type": "ZIS::Flow",      "properties": {        "name": "ticket-created-flow",        "definition": {          "StartAt": "ZendeskTicketCreated",          "States": {            "ZendeskTicketCreated": {              "Type": "Action",              "ActionName": "zis:{integration_name}:action:action_post_ticket_data",              "Parameters": {                "ticketId.$": "$.input.ticket_event.ticket.id",                "ticketStatus.$": "$.input.ticket_event.ticket.status",                "ticketPriority.$": "$.input.ticket_event.ticket.priority"              },              "End": true            }          }        }      }    },    "jobspec_handle_ticket_event": {      "type": "ZIS::JobSpec",      "properties": {        "name": "handle-ticket-created-event",        "event_source": "support",        "event_type": "ticket.TicketCreated",        "flow_name": "zis:{integration_name}:flow:ticket-created-flow"      }    }  }}

Don’t forget to replace {integration_name} with the integration name and {external_target_url} with the URL you obtained from https://webhook.site/, then save the file.

Deploying and testing the integration

After creating your my_zis_bundle.json bundle file, you can deploy and test the integration by completing the following steps:

Private integrations can only be installed on the Suite Growth plan or above or the Support Professional plan or above.

Uploading the bundle

The first step to deploying the integration is to upload the bundle by making an API request to the Create or Update Bundle endpoint.

Using Postman

  1. In Postman, select File > New > HTTP Request.

  2. In the Postman request editor, enter the Upload or Update Bundle endpoint:

    https://{subdomain}.zendesk.com/api/services/zis/registry/{integration_name}/bundles

    Replace {subdomain} with your Zendesk subdomain and {integration_name} with your registered integration name.

  3. Select POST as the method on the left side.

  4. Click the Body tab below your request path. Make sure the raw and JSON options are selected and paste the content from your my_zis_bundle.json file.

  5. Click the Authorization tab, and under Type, select Basic Auth, and enter your Zendesk admin credentials.

  6. Click Send.

ZIS will perform some basic validation of the bundle and report any issues in the response.

If the request is successful, it returns an empty 200 OK response.

The request and response should look like this in Postman:

Using cURL

In your command line interface, navigate to the folder that contains your my_zis_bundle.json file.

curl https://{subdomain}.zendesk.com/api/services/zis/registry/{integration_name}/bundles \  -d @my_zis_bundle.json \  -H "Content-Type: application/json" \  -v -u {email}:{password} -X POST

Installing the job spec

The next deployment step is to install the job spec specified in your bundle. ZIS will get the job spec from the bundle you just uploaded.

To install the job spec, make an API request to the Install JobSpec endpoint specifying your job spec name using the following format: zis:{integration_name}:job_spec:{job_spec_name}.

Using Postman

  1. In Postman, select File > New > HTTP Request.

  2. In the Postman request editor, enter the Install JobSpec endpoint:

    https://{subdomain}.zendesk.com/api/services/zis/registry/job_specs/install

    Replace {subdomain} with your Zendesk subdomain.

  3. Add a query parameter named job_spec_name with a value of zis:{integration_name}:job_spec:handle-ticket-created-event.

    Replace {integration_name} with your registered integration name.

  4. Select POST as the method on the left side.

  5. Click the Authorization tab, select Basic Auth as the type, and enter your Zendesk admin credentials.

  6. Click Send.

If the request is successful, it returns an empty 200 OK response.

The request and response should look like this in Postman:

Using cURL

curl "https://{subdomain}.zendesk.com/api/services/zis/registry/job_specs/install?job_spec_name=zis:{integration_name}:job_spec:handle-ticket-created-event" \  -v -u {email}:{password} -X POST

Make sure to enclose the endpoint path in quotes because it contains special characters.

Testing the integration

You can test your integration by creating a new ticket in Zendesk.

  1. In Zendesk, create a ticket and give it a status and priority.

    You can use the Zendesk Agent Workspace or make the following curl request:

    curl https://{subdomain}.zendesk.com/api/v2/tickets.json \  -d '{"ticket": {"subject": "My printer is on fire!", "priority": "urgent", "status": "open", "comment": { "body": "The smoke is very colorful." }}}' \  -H "Content-Type: application/json" -v -u {email_address}:{password} -X POST
  2. Navigate to your webhook.site dashboard https://webhook.site/#!/{external_target_url}, replacing {external_target_url} with your unique target URL.

    You should see a header with the ticket id as well as a JSON payload with the ticket status and priority.

If nothing happens, a good starting point for troubleshooting is checking the integrations log in the Zendesk Admin Center:

  1. Sign into your Zendesk account as a admin.

  2. In Admin Center, click Apps and integrations in the sidebar, then select Integrations > Logs.

For more information, see Viewing the integrations log in the Zendesk help center.

Congratulations, you just created your first ZIS integration from scratch.

Note: Remember to update the external target URL in your bundle seven days after getting the URL from webhook.site. On the webhook.site free plan, these URLs expire after seven days and your integration will stop working. Simply update the URL in your bundle and use the Upload or Update Bundle endpoint to update it.