The SignifAI Community Hub

Welcome to the SignifAI Community Hub.
This is the place for you to find something new, express your thoughts, share and collaborate with other people. You'll find comprehensive guides and documentation to help you start working with SignifAI as quickly as possible, as well as support if you get stuck. Let's jump right in!

Webhook

Consuming a Webhook

SigniAI’s Webhook lets other application to be notified about the following:

  • Issue Activation
    Every time a new Issue is activated (when an issue is actually going to be visible in the UI).
  • Issue Closure
    Every time an Issue state is closed (no matter if auto closed, closed due to correlation or fixed).
  • Issue Acknowledgment
    Every Time an issue is acknowledged (this is due to UI acknowledgment or 2-way integration with other incident management platforms).
  • Incidents Addition
    Every time there is a new incident in an existing issue. (known limit - the webhook support up to 100 latest incidents update to prevent high load and too large messages).
  • Incidents Updated
    When incidents that are related to the issue were updated.
  • Correlation Event
    Every time there is a merge event (aka correlation).
  • Priority Change
    When an issue’s priority is changed.
  • New Teams Association
    When a new team is associated with the issue.

SignifAI will send the event's details via HTTPS POST. Webhooks are configured on a Team basis. To configure a Webhook, edit the desired Team and add a new Webhook notification channel.

Enabling the webhook endpoint

If the Webhook option is not available as a channel it should first be enabled as an endpoint.
Enabling the endpoint can be done via:

  1. Go to https://app.signifai.io/sensor/webhook
  2. Click on Activate

Request Format

All webhooks are issued with the HTTP POST method, the body is formatted in JSON. The system expects the endpoint will return a successful HTTP code (2XX), in case of a failure the system retry sending the message for 1000 times.

The JSON Schema of the request is defined below.

Name
Type
Description

trigger_events

List[Enum(activated, closed, acknowledged, incidents_added, issues_merged)]

List of events that caused the webhook to be triggered

self_url

Href

A link to the UI where the issue can be seen

id

String

The Issue unique identifier

title

String

description

String

priority

Enum (Critical, High, Medium, Low)

state

Enum (Active, Closed, Acknowledged)

is_correlated

Boolean

True if the issue is correlated

is_root

Boolean

True if the issue is the root correlation set of issues. Issues are correlated by merging two Issues and forming a parent and a child relationship, the top-most Issue is the root. There is exactly one root for a set of correlated issues.

created_on

String (ISO Format)

modified_on

String (ISO Format)

activated_on

String (ISO Format)

closed_on

String (ISO Format)

sources

List[String]

List of the different sources that were used to send the Alerts into SignifAI (for example: AWS)

teams

List[Team]

List of teams that are associated to the issue.
Each team contains an id and the name of the team that.
For example: [{"id": "some id", "name": "team name"}]

teams[].id

String

teams[].name

String

correlated_issues

List[String]

List of correlated issues ids that were correlated together

incidents

List[Incident]

List of incidents that are attached to the Issue.
The list will contain only the latest 100 incidents.

incidents[].id

String

incidents[].events_count

Integer

The number of events used to create the Incident

incidents[].title

String

incidents[].description

String

incidents[].labels

Dictionary[String, String]

A string to string mapping of the Incidents labels. Labels represent the unique entities that are used to describe the Incident.

incidents[].priority

Enum (Critical, High, Medium, Low)

incidents[].sources

List[String]

incidents[].state

Enum(open, closed)

incidents[].opened_on

String (ISO Format)

incidents[].closed_on

String (ISO Format)

incidents[].modified_on

String (ISO Format)

JSON Schema

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "definitions": {
    "Labels": {
      "type": "object",
      "properties": {},
      "patternProperties": {
        ".*": {
          "type": "string"
        }
      },
      "additionalProperties": {
        "type": "string"
      }
    },
    "Incident": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "state": {
          "type": "string",
          "enum": [
            "open",
            "closed"
          ]
        },
        "priority": {
          "type": "string",
          "enum": [
            "critical",
            "high",
            "medium",
            "low"
          ]
        },
        "sources": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "labels": {
          "$ref": "#/definitions/Labels"
        },
        "events_count": {
          "type": "integer",
          "minimum": 0
        },
        "opened_on": {
          "type": "string"
        },
        "closed_on": {
          "type": "string"
        },
        "modified_on": {
          "type": "string"
        }
      },
      "required": [
        "id",
        "title",
        "state",
        "priority",
        "sources",
        "labels",
        "events_count",
        "opened_on",
        "modified_on"
      ],
      "additionalProperties": false
    }
  },
  "type": "object",
  "properties": {
    "trigger_events": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "activated",
          "closed",
          "acknowledged",
          "incidents_added",
          "issues_merged"
        ]
      }
    },
    "self_url": {
      "type": "string",
      "format": "uri"
    },
    "id": {
      "type": "string"
    },
    "title": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "priority": {
      "type": "string",
      "enum": [
        "critical",
        "high",
        "medium",
        "low"
      ]
    },
    "state": {
      "type": "string",
      "enum": [
        "active",
        "close",
        "acknowledged"
      ]
    },
    "is_correlated": {
      "type": "boolean"
    },
    "is_root": {
      "type": "boolean"
    },
    "sources": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "teams": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": false
      }
    },
    "correlated_issues": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "incidents": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/Incident"
      }
    },
    "created_on": {
      "type": "string"
    },
    "modified_on": {
      "type": "string"
    },
    "closed_on": {
      "type": "string"
    },
    "activated_on": {
      "type": "string"
    }
  },
  "required": [
    "trigger_events",
    "self_url",
    "id",
    "title",
    "priority",
    "state",
    "is_correlated",
    "is_root",
    "sources",
    "teams",
    "correlated_issues",
    "incidents",
    "created_on",
    "modified_on",
    "activated_on"
  ],
  "additionalProperties": false
}

Authentication

Every webhook trigger will contain the X-Signifai-Signature. The signature is the HMAC on the message body and the secret. The secret can be obtained when configuration a Webhook channel. The secret must be entered as base64 format and with a minimum length of 16 characters.

The signing algorithm is as follows (in pseudo-code):

TO_BASE64(HMACH_SHA256(FROM_BASE64(secret), request.body))

Verifying the signature (examples)

import hashlib
import hmac
import base64

secret = "<You secret here as base64>"
signature = hmac.new(base64.b64decode(secret), request.body, hashlib.sha256).digest()

# Verify the signature
assert signature == base64.b64decode(request.headers['X-Signifai-Signature']), "Signature does not match"
package com.company;

import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;


public class Example {
    public static boolean verifySignature(String body, String secret, String signatureHeader) throws NoSuchAlgorithmException, InvalidKeyException {
        Mac hmac = Mac.getInstance("HmacSHA256");

        byte[] secretBytes = Base64.getDecoder().decode(secret);

        SecretKeySpec secretKey = new SecretKeySpec(secretBytes, "HmacSHA256");
        hmac.init(secretKey);

        byte[] computedSignature = hmac.doFinal(body.getBytes());

        return Arrays.equals(computedSignature, signatureBytes);
    }
}
namespace SignifAI
{
    using System;
    using System.Text;
    using System.Linq;
    using System.Security.Cryptography;

    class Example
    {
        /// <summary>Verify the webhook signature</summary>
        /// <param name="body">The body of the request, as string</param>
        /// <param name="secret">The secret used by the customer</param>
        /// <param name="signatureHeader">The content of the X-Signifai-Header</param>
        /// <returns>Returns true if the signature is correct, false otherwise.</returns>
        public static bool VerifySignature(string body, string secret, string signatureHeader)
        {
            // First make sure to remove pesky whitespaces
            secret = secret.Trim();
            signatureHeader = signatureHeader.Trim();

            byte[] signature = Convert.FromBase64String(signatureHeader);

            // If the signature is not in the correct size, it's definatly wrong since SHA256 is always 256 bit long
            if (signature.Length != 32)
                return false;

            byte[] computedHash;
            
            byte[] secretBytes = Convert.FromBase64String(secret);
            using (var hmac = new HMACSHA256(secretBytes))
            {
                computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(body));
            }

            for (int i = 0; i < signature.Length; i++)
            {
                if (computedHash[i] != signature[i])
                {
                    return false;
                }
            }

            return true;
        }
    }
}
var CryptoJS = require("crypto-js");

function verifySignature(body, secret, signatureHeader) {
    var hash = CryptoJS.HmacSHA256(body, secret);
    return CryptoJS.enc.Base64.stringify(hash) == signatureHeader
}

The JavaScript implementation is using CryptoJS, to install use the shell command npm install crypto-js

Need help with the integration?

Contact us at: support@signifai.io and we will be happy to help.