Handling webhook notifications

Prev Next

In this section, learn about the webhook notification request’s headers and body. It’s up to your application to parse the request, verify its signature, and send response.

Request

When an alert is triggered, the Secure Edge Portal sends an HTTP POST request to the webhook's configured URL. The headers and the JSON body of the POST request are described below.

The webhook notification request looks like this:

curl -X POST \
  -H '<your_additional_headers>' \
  -H "Content-type:application/json"
  -H "X-Iotium-Signature:<IOTIUM_SIGNATURE>" \
  -H "X-Iotium-Timestamp:<TIMESTAMP>" \
  -d '{<WEBHOOK_NOTIFICATION_POST_BODY>}' \
'<your_webhook_url>'

Headers

The webhook notification request has the following ioTium-specific headers:

HeaderDescription

Your additional headers

Additional HTTP request headers you wanted to include in the notification request. When adding the webhook, you specified up to three headers with total header length of up to 2048 characters.

X-Iotium-Signature

Signature created from this notification request's timestamp and body. For more details, see Verifying webhook signature.

X-Iotium-Timestamp

POSIX timestamp in milliseconds, specifying when we sent this notification request.

Body

The webhook notification body (payload) is a JSON object that describes the alert that triggered the notification. It also describes the target resource (iNode, iNode network, service, etc.) to which the alert applies.

The sections that follow describe the payload for each alert type.

Node Status Alert

The node status (iNode Status) alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is NODE_STATE_CHANGE.

display_type

Displayable text of the type field. For this alert notification, it is iNode Status.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of yournode that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node that triggered the alert.

status

Status of your node that triggered the alert:
ALIVE — the node can connect to the Secure Edge Portal
UNREACHABLE — the node can't connect to the Secure Edge Portal

The node status alert notification payload looks like this:

{
  "type":"NODE_STATE_CHANGE",
  "node":{
    "id":"<your_inode_id>",
    "name":"<your_inode_name>"
  },
  "profile":{
    "id":"<your_inode_profile_id>",
    "name":"<your_inode_profile_name>"
  },
  "id":"<your_notification_id>",
  "status":"<your_inode_status>",
  "display_type":"iNode Status",
  "hardware_serial_number":"<your_inode_serial_number>",
  "organization":{
    "id":"<your_org_id>",
    "name":"<your_org_name>"
  },
  "alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
  "created_at":"2020-01-01T00:00:00.000000000Z",
  "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

Remote Network Connection Status

The Remote Network Connection Status alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is TUNNEL_STATE_CHANGE.

display_type

Displayable text of the type field. For this alert notification, it is Remote Network Connection Status.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of your node that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node that triggered the alert.

network

Details of your local network:
id — Your network ID
name — Your network name

peer_node

Details of your remote node:
id — Your remote node ID
name — Your remote node name

peer_node_profile

Details of your remote node profile:
id — Your remote node profile ID
name — Your remote node profile name

peer_network

Details of the remote network on your remote node:
id — Your remote network ID
name — Your remote network name

tunnel

Details of your local network connection:
id — Your connection ID
name — Your connection name

peer_tunnel

Details of your remote network connection:
id — Your remote connection ID
name — Your remote connection name

status

Status of your connection to the remote network that triggered the alert:
CONNECTED — The remote network has connected successfully.
TERMINATED — The remote network failed to connect or the connection dropped after initially connecting.

The Remote Network Connection Status alert notification payload looks like this:

{
  "type":"TUNNEL_STATE_CHANGE",
  "node":{
    "id":"<your_inode_id>",
    "name":"<your_inode_name>"
  },
  "profile":{
    "id":"<your_inode_profile_id>",
    "name":"<your_inode_profile_name>"
  },
  "network":{
    "id":"<your_network_id>",
    "name":"<your_network_name>"
  },
  "peer_node":{
    "id":"<your_remote_inode_id>",
    "name":"<your_remote_inode_name>"
  },
  "peer_node_profile":{
    "id":"<your_remote_inode_profile_id>",
    "name":"<your_remote_inode_profile_name>"
  },
  "peer_network":{
    "id":"<your_remote_network_id>",
    "name":"<your_remote_network_name>"
  },
  "tunnel":{
    "id":"<your_network_connection_id>",
    "name":"<your_network_connection_name>"
  },
  "peer_tunnel":{
    "id":"<your_remote_network_connection_id>",
    "name":"<your_remote_network_connection_name>"
  },
  "id":"<your_notification_id>",
  "status":"<your_remote_network_connection_status>",
  "display_type":"Remote Network Connection Status",
  "hardware_serial_number":"<your_inode_serial_number>",
  "organization":{
    "id":"<your_org_id>",
    "name":"<your_org_name>"
  },
  "alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
  "created_at":"2020-01-01T00:00:00.000000000Z",
  "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

Service Status

The Service Status alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is SERVICE_STATE_CHANGE.

display_type

Displayable text of the type field. For this alert notification, it is Service Status.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of your node that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node.

service

Details of your service that triggered the event:
id — Your service ID
name — Your service name

container_status

Status of all the containers in your service, expressed as key-value pairs of the container name and container status. Status of a container can be:
WAITING — Your container is being created, or is starting, or is paused
RUNNING — Your container is running
TERMINATED — Your container has exited due to success or failure
UNKNOWN — Your container status is unavailable because the node isn’t ALIVE

running_containers

Number of containers running in your service and the total number of containers, separated by the slash ( / ) character.

status

Status of your service that triggered the alert:
HEALTHY — All containers in the service are in RUNNING status
UNHEALTHY — The containers in the service are in disparate status
TERMINATED — All containers in the service are in TERMINATED status

The Service Status alert notification payload looks like this:

{
  "type":"SERVICE_STATE_CHANGE",
  "node":{
    "id":"<your_inode_id>",
    "name":"<your_inode_name>"
  },
  "profile":{
    "id":"<your_inode_profile_id>",
    "name":"<your_inode_profile_name>"
  },
  "service":{
    "id":"<your_service_id>",
    "name":"<your_service_name>"
  },
  "id":"<your_notification_id>",
  "status":"<your_service_status>",
  "display_type":"Service Status",
  "hardware_serial_number":"<your_inode_serial_number>",
  "container_status":{"<your_container_name>":"<your_container_status>"},
"running_containers":"<your_running_containers_count>/<your_total_containers_count>",
  "organization":{
    "id":"<your_org_id>",
    "name":"<your_org_name>"
  },
  "alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
  "created_at":"2020-01-01T00:00:00.000000000Z",
  "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

Standalone Mode Expiry

The Standalone Mode Expiry alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is HEADLESS_EXPIRY.

display_type

Displayable text of the type field. For this alert notification, it is Standalone Mode Expiry.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of your node that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node that triggered the event.

max_headless_time

Your node's standalone mode expiry period in minutes.

headless_expire_at

Date and time when your node's standalone mode expires in ISO 8601 format.

headless_expire_percent

Percentage of your node's standalone mode expiry period that is used up. If 80% or more is used up, the alert is triggered.

is_headless_expired

Has your node's standalone mode expired? (true or false.) If true, the alert is triggered.

The Standalone Mode Expiry alert notification payload looks like this:

{
    "type":"HEADLESS_EXPIRY",
    "node":{
        "id":"<your_inode_id>",
        "name":"<your_inode_name>"
    },
    "profile":{
      "id":"<your_inode_profile_id>",
      "name":"<your_inode_profile_name>"
    },
    "id":"<your_notification_id>",
    "max_headless_time":10,
    "headless_expire_at":"2020-01-01T00:00:00.000000000Z",
    "headless_expire_percent":80,
    "is_headless_expired":false,
    "last_contact_at":"2020-01-01T00:00:00.000000000Z",
    "hardware_serial_number":"<your_inode_serial_number>",
    "display_type":"Standalone Mode Expiry"
    "organization":{
        "id":"<your_org_id>",
        "name":"<your_org_name>"
    },
    "alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
    "created_at":"2020-01-01T00:00:00.000000000Z",
    "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

iNode Certificate Expiry

The node certificate expiry (iNode Certificate Expiry) alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is CERT_EXPIRY.

display_type

Displayable text of the type field. For this alert notification, it is iNode Certificate Expiry.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of your node that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node that triggered the event.

cert_expire_at

Date and time when your node certificate expires in ISO 8601 format.

cert_expire_percent

Percentage of your node's certificate validity period that is used up. If 80% or more is used up, the alert is triggered.

is_cert_expired

Has your node's certificate expired? (true or false.) If true, the alert is triggered.

The iNode Certificate Expiry alert notification payload looks like this:

{
  "type":"CERT_EXPIRY",
  "id":"<your_notification_id>",
  "certs":[{
    "node":{
     "id":"<your_inode_id>",
     "name":"<your_inode_name>"
    },
    "profile":{
      "id":"<your_inode_profile_id>",
      "name":"<your_inode_profile_name>"
    },
    "organization":{
      "id":"<your_org_id>",
      "name":"<your_org_name>"
    },
    "cert_expire_at":"2020-01-01T00:00:00.000000000Z",
    "hardware_serial_number":"<your_inode_serial_number>",
    "cert_expire_percent":80,
    "is_cert_expired":false
  }],
"alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
  "display_type":"iNode Certificate Expiry",
  "created_at":"2020-01-01T00:00:00.000000000Z",
  "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

iNode IP Address Change

The iNode IP Address Change alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is NODE_IP_CHANGE.

display_type

Displayable text of the type field. For this alert notification, it is iNode IP Address Change.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of your node that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node that triggered the event.

from

IP address of your node before the change.

to

IP address of your node after the change.

status

Your node's IP address change that triggered the alert:
PUBLIC IP — Your node's public IP address changed
PRIVATE IP — Your node's private IP address changed

The iNode IP Address Change alert notification payload looks like this:

{
  "type":"NODE_IP_CHANGE",
  "node":{
    "id":"<your_inode_id>",
    "name":"<your_inode_name>"
  },
  "profile":{
    "id":"<your_inode_profile_id>",
    "name":"<your_inode_profile_name>"
  },
  "id":"<your_notification_id>",
  "status":"<your_inode_which_ip_changed>",
  "display_type":"iNode IP Address Change",
  "hardware_serial_number":"<your_inode_serial_number>",
  "from":"<your_from_ip_address>",
  "to":"<your_to_ip_address>",
  "organization":{
    "id":"<your_org_id>",
    "name":"<your_org_name>"
  },
  "alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
  "created_at":"2020-01-01T00:00:00.000000000Z",
  "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

iNode Upgrade Status

The node upgrade status (iNode Upgrade Status) alert notification payload has the following fields:

FieldDescription

type

Metric type of your triggered alert. For this alert notification, it is NODE_UPGRADE.

display_type

Displayable text of the type field. For this alert notification, it is iNode Upgrade Status.

id

Unique identifier for your notification. When we retry sending the notification, this ID remains the same.

alert

Details of your triggered alert:
id — Your alert ID
name — Your alert name

event_occurred_at

Date and time when your alert triggered in ISO 8601 format.

created_at

Date and time when we detected your alert triggering in ISO 8601 format.

organization

Details of your organization:
id — Your organization ID
name — Your organization name

node

Details of your node that triggered the alert:
id — Your node ID
name — Your node name

profile

Your node profile details:
id — Your node profile ID
name — Your node profile name

hardware_serial_number

Serial number of your node that triggered the event.

from

Version of your node before the upgrade (if upgrade status is SUCCESSFUL).

to

Version of your node after the upgrade (if upgrade status is SUCCESSFUL).

status

Upgrade status of your node that triggered the alert:
ENABLED — Upgrade has been enabled for your node
DISABLED — Upgrade has been disabled for your node
SUCCESSFUL — Upgrade was successful for your node
FAILED — Upgrade has failed for your node

The iNode Upgrade Status alert notification payload looks like this:

{
  "type":"NODE_UPGRADE",
  "node":{
    "id":"<your_inode_id>",
    "name":"<your_inode_name>"
  },
  "profile":{
    "id":"<your_inode_profile_id>",
    "name":"<your_inode_profile_name>"
  },
  "id":"<your_notification_id>",
  "status":"<your_inode_upgrade_status>",
  "display_type":"iNode Upgrade Status",
  "hardware_serial_number":"<your_inode_serial_number>",
  "from":"<your_from_version>",
  "to":"<your_to_version>",
  "organization":{
    "id":"<your_org_id>",
    "name":"<your_org_name>"
  },
  "alert":{
    "id":"<your_alert_id>",
    "name":"<your_alert_name>"
  },
  "created_at":"2020-01-01T00:00:00.000000000Z",
  "event_occured_at":"2020-01-01T00:00:00.000000000Z"
}

Responding to a webhook notification request

For all webhook notification requests, the response 2XX is success. The response 3XX and redirect of the request may occur at most five times. All other responses are considered failures.

Timeout and Retry

A webhook notification request may take up to five seconds to complete. If the connection fails, times out, or if the request fails with a 5XX response, a retry occurs after one minute. If the request still fails after the retry, there is no additional retry.

If the webhook notification request continuously fails 10 times, a WEBHOOK_FAILED event occurs and the webhook is disabled.

Verifying webhook signature

The webhook notification HTTP POST request contains a header with a signature generated from a cryptographic digest of the notification request body. When your application receives the request, we advise you to verify the signature by calculating the same digest and comparing it to the one in the header. Verifying the signature helps you to validate the integrity and origin of the webhook notification.

Following are the steps to verify the signature:

  1. Extract the timestamp from the X-Iotium-Timestamp header field and the signature from the X-Iotium-Signature header field of the webhook notification request.
  2. Compute the difference between the current timestamp and the extracted timestamp. Don't trust the payload if the difference exceeds your tolerance.
  3. Compute the expected signature this way:
    Shell
    signature = Hex-encoded(HMACSHA256(<>,>,>
    The secret is the value of the secret field you saved from the response to the POST request to add webhook. Don’t use a pretty formatted request body for this computation.
    Following is a code snippet for computing the expected signature using Python (Version 3.8.2):
    Python
    def genSignature(secret:str, timestamp:str, body:str) -> str:
        import hmac
        import hashlib
        message:str = "%s.%s" % (timestamp, body)
        return hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    Following is a code snippet for computing the expected signature using Java (Version 1.8.0_191):
    Java
    import java.nio.charset.Charset;
    import java.security.GeneralSecurityException;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    
    public String getSignature(String secret, String timestamp, String body) {
         String HMAC_SHA256_ALGORITHM = "HmacSHA256";
         String hmac_hex = null;
         try {
    	   SecretKeySpec signingKey = new    SecretKeySpec(secret.getBytes(Charset.defaultCharset()),
    					HMAC_SHA256_ALGORITHM);
    	  Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
    	  mac.init(signingKey);
    	  String message = timestamp.concat(".").concat(body);
    	  byte[] rawHmac = mac.doFinal(message.getBytes(Charset.defaultCharset()));
    			hmac_hex = bytesToHex(rawHmac);
    		} catch (GeneralSecurityException e) {
    			throw new IllegalArgumentException();
    		}
    		return hmac_hex;
    	}
    
    public String bytesToHex(byte[] bytes) {
         char[] hexArray = "0123456789abcdef".toCharArray();
         char[] hexChars = new char[bytes.length * 2];
         for (int j = 0; j < bytes.length; j++) {
              int v = bytes[j] & 0xFF;
    	    hexChars[j * 2] = hexArray[v >>> 4];
    	    hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    	}
          return new String(hexChars);
    }
    4. Compare the expected signature with the signature extracted from the X-Iotium-Signature header field. If both are identical, you can trust the payload. Otherwise, don't trust the payload.