Extending your first integration: Using ZIS Links
In the Using ZIS to obtain Slack OAuth token, you learnt how to start a Slack OAuth flow using ZIS Connections API to obtain an access token. This token can be used to make authenticated REST API calls. In this tutorial, you’ll learn how to store the association between a Zendesk ticket and a Slack message. Then understand how to make use of this to update the Slack thread when there is an update to the ticket (such as adding a new comment) using the access token.
Understanding ZIS Links
Zendesk Integration Services (ZIS) offers a service called ZIS Links specifically designed to store the association (link) between two objects. The association can be one-to-one such as a ticket ID to a Slack thread, or one-to-many such as a ticket ID to multiple JIRA issues. The service supports creating, updating, and deleting links.
ZIS Flow has native support for links in the form of CreateLink
, LoadLinks
, PatchLink
, and DeleteLink
ZIS Action state types. All actions are scoped to your integration and the account for the flow.
Parameters
link_type
: Thelink_type
identifies the type of link. It along with theleft_object_name
andright_object_name
uniquely identifies the link. In cases where the value oflink_type
represents a reference path, it should be namedlink_type.$
.left_object_name
: Theleft_object_name
represents the "left" side of the link. It along with thelink_type
andright_object_name
uniquely identifies the link. In the case where the value ofleft_object_name
represents a reference path, it should be namedleft_object_name.$
.right_object_name
: Theright_object_name
represents the "right" side of the link. It along with thelink_type
andleft_object_name
uniquely identifies the link. In cases where the value ofright_object_name
represents a reference path, it should be namedright_object_name.$
.
The parameter values can be 3 to 256 characters and contain numbers, letters, and colon (:), forward slash (/), underscore (_), dash (-), and period (.) special characters.
CreateLink
The CreateLink
action is used to create a link between two objects. link_type
, left_object
and right_object
are required when creating a link. The CreateLink
Action takes the following form. Each object can have an optional metadata
associated with it as well.
"CreateLink": {
"Type":"Action",
"ActionName":"zis:common:action:CreateLink",
"Parameters":{
"link_type":"{link_type}",
"left_object":{
"name":"{left_object_name}",
"metadata": {}
},
"right_object":{
"name":"{right_object_name}",
"metadata": {}
}
},
"Next":"Done"
}
LoadLinks
The LoadLinks
action is used to look up the link given the link_type
, either left_object_name
, right_object_name
, or both. It supports the use of *
in the object's name and can be used to perform "like" searches such as left_object_name: foo*
. This matches all left_object_name
having foo
as its prefix. The asterisk (*) can only be at the end of a LoadLinks
operation.
Note: The search is not performed on metadata
of each object, but only on the object names.
The result of the LoadLinks
operation is stored in ResultPath
. The LoadLinks
action takes the following form:
"LoadLinks": {
"Type":"Action",
"ActionName":"zis:common:action:LoadLinks",
"Parameters":{
"link_type":"{link_type}",
"left_object_name":"{left_object_name}",
"right_object_name":"{right_object_name}"
},
"ResultPath":"{store_at_reference_path}",
"Next":"{next_state}"
}
Delete Link
DeleteLink
is used to delete a link. link_type
, left_object
, and right_object
are required when deleting a link. The DeleteLink
action takes the following form:
"DeleteLink":{
"Type":"Action",
"ActionName":"zis:common:action:DeleteLink",
"Parameters":{
"link_type":"{link_type}",
"left_object_name":"{left_object_name}",
"right_object_name":"{right_object_name}"
},
"Next":"{next_state}"
}
Patch Link
PatchLink
is used to update the object names (left or right or both) and its associated metadata. It requires the old link names left_object_name
and right_object_name
and the new objects as right_object
and left_object
.
"PatchLink":{
"Type":"Action",
"ActionName":"zis:common:action:PatchLink",
"Parameters":{
"link_type":"{link_type}",
"left_object_name":"{left_object_name}",
"right_object_name":"{right_object_name}",
"left_object":{
"name":"{new_name}"
},
"right_object":{
"name":"{new_name}"
},
},
"ResultPath":"{reference_path_to_store_results}",
"Next":"{next_state}"
}
Sending a Slack notification
You'll learn how to make use of ZIS Links to store the association between a Zendesk ticket and a Slack thread, then use that association to update a Slack thread. The logic for a flow is shown below. In this tutorial, you’ll use TicketCreated
or CommentAdded
events as triggers.

Creating and uploading a ZIS Bundle
-
In your text editor, create a file named send_slack_notification_bundle.json and paste the following code:
{
"zis_template_version": "2019-10-14",
"name": "Send Slack notification when ticket is updated",
"description": "Send Slack notification when ticket is updated",
"resources": {
"TicketCreatedJobSpec": {
"type": "ZIS::JobSpec",
"properties": {
"name": "TicketCreatedJobSpec",
"event_source": "support",
"event_type": "ticket.TicketCreated",
"flow_name": "zis:{integration_name}:flow:SendSlackNotification"
}
},
"CommentAddedJobSpec": {
"type": "ZIS::JobSpec",
"properties": {
"name": "CommentAddedJobSpec",
"event_source": "support",
"event_type": "ticket.CommentAdded",
"flow_name": "zis:{integration_name}:flow:SendSlackNotification"
}
},
"SendSlackNotification": {
"type": "ZIS::Flow",
"properties": {
"name": "SendSlackNotification",
"definition": {
"StartAt": "GetLinkedMessage",
"States": {
"GetLinkedMessage": {
"Type": "Action",
"ActionName": "zis:common:action:LoadLinks",
"Parameters": {
"link_type": "ticket_to_message",
"left_object_name.$": "ticket_id:{{$.input.ticket_event.ticket.id}}"
},
"ResultPath": "$.get_linked_message_response",
"Next": "CheckLink"
},
"CheckLink": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.get_linked_message_response.count",
"NumericEquals": 0,
"Next": "SendMessageOnTicketCreate"
},
{
"Variable": "$.get_linked_message_response.count",
"NumericEquals": 1,
"Next": "ExtractThreadId"
}
]
},
"SendMessageOnTicketCreate": {
"Type": "Action",
"ActionName": "zis:{integration_name}:action:PostToSlack",
"Parameters": {
"text.$": ":rotating_light: A <https://{{$.subdomain}}.zendesk.com/agent/tickets/{{$.input.ticket_event.ticket.id}}| ticket> was created!",
"thread_ts": 0,
"access_token.$": "$.connections.slack.access_token"
},
"ResultPath": "$.send_message_response",
"Next": "CreateLink"
},
"ExtractThreadId": {
"Type": "Action",
"ActionName": "zis:common:transform:Jq",
"Parameters": {
"expr": ".right_object.name | split(\":\")[1]",
"data.$": "$.get_linked_message_response.links[0]"
},
"ResultPath": "$.thread_id",
"Next": "ThreadMessageOnTicketUpdate"
},
"ThreadMessageOnTicketUpdate": {
"Type": "Action",
"ActionName": "zis:{integration_name}:action:PostToSlack",
"Parameters": {
"text.$": "$.input.ticket_event.comment.body",
"thread_ts.$": "$.thread_id",
"access_token.$": "$.connections.slack.access_token"
},
"Next": "Done"
},
"CreateLink": {
"Type": "Action",
"ActionName": "zis:common:action:CreateLink",
"Parameters": {
"link_type": "ticket_to_message",
"left_object": {
"name.$": "ticket_id:{{$.input.ticket_event.ticket.id}}"
},
"right_object": {
"name.$": "thread_ts:{{$.send_message_response.message.ts}}"
}
},
"Next": "Done"
},
"Done": {
"Type": "Succeed"
}
}
}
}
},
"PostToSlack": {
"type": "ZIS::Action::Http",
"properties": {
"name": "PostToSlack",
"definition": {
"method": "POST",
"url": "https://slack.com/api/chat.postMessage",
"headers": [
{
"key": "Authorization",
"value.$": "Bearer {{$.access_token}}"
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"requestBody": {
"text.$": "$.text",
"channel": "{slack_channel}",
"thread_ts.$": "$.thread_ts"
}
}
}
}
}
}
Replace the following placeholders:
{integration_name}
with the integration name when you registered your integration. See Building your first ZIS integration{slack_channel}
with your Slack channel name
-
Save the file.
-
From the command line editor, make a cURL request to the Registry API to upload the bundle:
curl \
--request POST \
--url https://{subdomain}.zendesk.com/api/services/zis/registry/{integration_name}/bundles \
--user '{email}:{password}' \
--header 'content-type: application/json' \
-d @send_slack_notification_bundle.json
Replace
{email}
and{password}
with your Basic Auth credentials. -
From the command line, run the
curl
command to enable the job spec. Note: If you have already enabled the job specTicketCreatedJobSpec
orCommentAddedJobSpec
in previous tutorials, you can skip this step.curl \
--request POST \
--url "https://{subdomain}.zendesk.com/api/services/zis/registry/job_specs/install?job_spec_name=zis:{integration_name}:job_spec:TicketStatusChangedJobSpec,zis:{integration_name}:job_spec:CommentAddedJobSpec" \
--user '{email}:{password}'
Testing the integration
Test the integration in Zendesk Support by creating a ticket and adding a comment. You should see a notification in your Slack channel. All comments added to the ticket should appear threaded.

Next: Extending your first integration: Triggering a ZIS Flow from external events