Introduction

Remember when we went through the Getting Started guide, there was the section to define webhooks as Consequences? This document will show you how to implement those and add them to the Zeleo Application you are developing. An example use of this could be integrating with Slack. An immensely popular commnication platform, a Zeleo Consequence could be used to send a notification to a Slack Channel when a Condition is true.

Consequence

The good news about this section is that a Zeleo Consequence is really very simple. What you are doing is allowing the Zeleo Creator to trigger an event in another system when certain conditions are met. What that means in practical terms is each of your Consequences will have an endpoint that will be sent a specific data object when fired, and you will use that information to process the event depending on the system you are integrating with. A simple exampke of this would be Slack. Assuming you have authentication all set up (click here to learn more about that), you will just need to take the data object and post the specified communication template to the specified channel.

Authentication

All data posted to your endpoint will be JWT encrypted as documented here. Make sure you take the token and decrypt it as documented in the JWT Decryption section before continuing. Once that is in place you will have a JSON object that is defined in the next section.

Data Object

The following is the data object that gets sent to your endpoint when a Consequence triggers:

{
	"teamConfig": [], // Any configuration fields for the Zeleo team that fired the event.
	"personConfig": [], // Configuration fields for the user who is the focus of the event.
	"event": {}, // The event that triggered the consequence.
	"zeleoEvent": {}, // The definition of the event; this uses some Zeleo internal data, so might be more than you need.
	"results": {}, // Data on the execution of the rule.
	"fields": [] // Fields set on the consequence. For instance if a Communication Template was specified in the rule consequence, it will be here.
}

Here’s a real example of this object as seen by our Slack Zeleo Application:

{
    "teamConfig": [
        {
            "name": "Team Name",
            "description": "The name of your team as defined in Slack.",
            "required": true,
            "fieldType": "String",
            "value": "Zeleo, Inc",
            "options": []
        }
    ],
    "personConfig": [
        {
            "name": "User Name",
            "description": "This is your Slack handle. Starts with an '@' symbol.",
            "fieldType": "String",
            "value": "@benjamin.flynn",
            "options": []
        },
        {
            "name": "Authorize Slack Channel",
            "description": "Click this to allow Zeleo access to your Slack team and define channel.",
            "required": true,
            "fieldType": "Authorization",
            "options": []
        }
    ],
    "event": {
        "created": null,
        "url": "https://github.com/Zeleo/zeleo/issues/3869",
        "milestone": 53,
        "private": "True",
        "repository": "zeleo",
        "action": "assigned",
        "assignee": "765c4096-8164-11e8-9476-0242ac110002",
        "state": "open",
        "updated": null,
        "components": [
            {
                "name": "Issue Assigned or Updated: [3869] Finish GitHub Application",
                "description": "Finish GitHub Application",
                "url": "https://github.com/Zeleo/zeleo/issues/3869"
            }
        ],
        "comment": "Let's make sure all the events that we want to are available.",
        "organization": "Zeleo"
    },
    "zeleoEvent": {
        "isTemplate": false,
        "name": "Issue",
        "id": "35a5b74e-5544-11e8-875c-0242ac110002",
        "objecttype": "json",
        "fields": [
            {
                "id": "235186d4-5545-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Private",
                "jsonKey": "private",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db15-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [
                    "True",
                    "False"
                ],
                "fieldType": "Boolean",
                "externalSource": false
            },
            {
                "id": "235186d1-5545-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Respository",
                "jsonKey": "repository",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db16-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "String",
                "externalSource": false
            },
            {
                "id": "ea62f1e2-5544-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Updated",
                "jsonKey": "updated",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db17-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "Date",
                "externalSource": false
            },
            {
                "id": "235186d2-5545-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Comment",
                "jsonKey": "comment",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db18-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "String",
                "externalSource": false
            },
            {
                "id": "ea62f1e3-5544-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Created",
                "jsonKey": "created",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db19-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "Date",
                "externalSource": false
            },
            {
                "id": "235186d3-5545-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "URL",
                "jsonKey": "url",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db1a-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "String",
                "externalSource": false
            },
            {
                "id": "ea62f1e0-5544-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Milestone",
                "jsonKey": "milestone",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db1b-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "String",
                "externalSource": false
            },
            {
                "id": "35a5b74f-5544-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "State",
                "jsonKey": "state",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db1c-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [
                    "closed",
                    "open"
                ],
                "fieldType": "MultipleChoice",
                "externalSource": false
            },
            {
                "id": "235186d5-5545-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Organization",
                "jsonKey": "organization",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db1d-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "String",
                "externalSource": false
            },
            {
                "id": "35a5b750-5544-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Action",
                "jsonKey": "action",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db1e-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [
                    "reopened",
                    "edited",
                    "labeled",
                    "closed",
                    "unlabeled",
                    "opened",
                    "assigned",
                    "demilestoned",
                    "milestoned",
                    "unassigned"
                ],
                "fieldType": "MultipleChoice",
                "externalSource": false
            },
            {
                "id": "ea62f1e1-5544-11e8-875c-0242ac110002",
                "event": "35a5b74e-5544-11e8-875c-0242ac110002",
                "name": "Assignee",
                "jsonKey": "assignee",
                "objectversion": "1.0",
                "isTemplate": false,
                "identifier": false,
                "nonce": "8603db1f-c5a7-11e8-81a6-0242ac110002",
                "objecttype": "json",
                "persist": false,
                "options": [],
                "fieldType": "Person",
                "externalSource": false
            }
        ],
        "serviceid": "1aa4666c-53ce-11e8-84d3-0242ac110002"
    },
    "results": {
        "cycleID": "OGVVKF",
        "timeStamp": "2018-10-01T18:26:33.351Z",
        "database": 467946,
        "stats": {
            "numRules": 10,
            "numBranches": 11,
            "evaluationTime": 70,
            "numActions": 3,
            "numEvaluated": 10,
            "numErrored": 0,
            "numSkipped": 1,
            "averageQueryTime": 5,
            "maxQueryTime": 12,
            "minQueryTime": 1
        }
    },
    "fields": [
        {
            "id": "c0e179bf-b22b-11e8-aef4-0242ac110002",
            "type": "Template",
            "name": "template",
            "value": "GitHub Issue assigned to _Benjamin _ for _Zeleo _!\n \n*URL*: https://github.com/Zeleo/zeleo/issues/3869 \n*Milestone*: 53 \n*Comment*:\n`Let's make sure all the events that we want to are available.  `"
        },
        {
            "id": "b4e6308c-b39a-11e8-b334-0242ac110002",
            "type": "String",
            "name": "slack_channel",
            "value": "ex-bjönd"
        }
    ]
}

So how would you use this? Well, when you receive this data, you will be provided in this object with any and all configuration information defined by the Team Administrator, User, and Rule Auther. The answer to that is very simple- you would take this and call out to the external system and perform the operation that would be approriate for that event. In this example it would be to send the Communication Template to the Slack Channel defined.

Authorization

At this point you might be asking yourself how you would authenticate with the service, in this example Slack. There’s a separate document specifically for this topic that you will need to read, but in short you will need to configure your service accordingly. Zeleo can add a button that uses OAuth2/OpenID Connect to permit a user and/or Team Administrator to authorize the connection to the external service. In the example of Slack, doing se sens the URL for the given channel to the callback URL which our service then stores so it know what URL to post information to. Again, this is probably the most complex topic for creating a Zeleo Application, so be sure to read this to learn how to properly authenticate your service.