Skip to main content

WebHooks

Working#

To integrate kelvin events with your own application, you need to have public and private keys which are required for signing and verifying data. These keys can be generated from the kelvin portal. You need to be an administrator or a super user in order to create these keys. (For more information on Roles check out this [link]). You can find the keys in Integrations section of myaccount on kelvin portal.

Creating a Web Hook.#

  1. Login to the kelvin portal.
  2. Click on the profile icon for a drop down to show up.

Integrations

  1. Select Company Profile from the dropdown.
  2. Click on the Integrations Tab in the Company Profile section
  3. Now Click on Create Integration button, once clicked a dialog box would show up.

Web hook

  1. Give a application id to your webhook.
  2. Now select webhook from the integration type dropdown which contains "API Key" and "Web Hook" as options.
  3. Now select the version of the webhook, it should be v2.0.
  4. Also, give the Application URL (if any) of your application to which data should be sent.
  5. Now click on Save and a CSV file is downloaded with public, private keys. These keys can be used for verifying the request source..

Data Format.#

Version v1.0 (About to deprecate)#

For this version, request body is sent in JSON format. Following is the typical data format.

{
"timestamp":
"signature":
"payload":{
"type":
"operation":
"data":{},
},
}

Device Ping Request Body Format:

{
"timestamp":
"signature":
"payload":{
"type":
"operation":
"data":{
"imei":
"interval":{
"collection":
"transmit":
},
"network":{
"sim": {
"rssi":
}
},
"timestamp":
"battery":
"battery_voltage":
"location": [
{
"hits": ,
"q": {
"waps": [
{
"macAddress":
},
{
"macAddress":
},
{
"macAddress":
}
],
"cts": [
{
"mnc":
"mcc":
"radioType":
"lac":
"cid":
}
]
},
"lng":
"accuracy":
"queriedAt":
"source":
"cachedAt":
"lat":
}
],
"temperature":
"light":
"acceleration":
},
},
}

Device Ping Request Body Example:

{
"timestamp": 1610308993220,
"signature": "ashfoeihs#29402",
"payload": {
"type": "devicePing",
"operation": "create",
"data": {
"imei": "30124123",
"interval": {
"collection": 1,
"transmit": 15
},
"network": {
"sim": {
"rssi": 12,
}
},
"timestamp": 1610308993220,
"battery": 92.34,
"battery_voltage": 3121,
"location": [
{
"hits": 1,
"q": {
"waps": [
{
"macAddress": "6c:31:0e:4b:1d:83"
},
{
"macAddress": "3c:51:0e:38:a4:c3"
},
{
"macAddress": "3c:51:0e:38:a4:c2"
}
],
"cts": [
{
"mnc": 1,
"mcc": 505,
"radioType": "lte",
"lac": 36871,
"cid": 17676
}
]
},
"lng": 116.0123039,
"accuracy": 60,
"queriedAt": 1644409702,
"source": "MIX",
"cachedAt": 1644409702,
"lat": -31.9238247
}
],
"temperature": [20.55, 21, 25, 27, 21.7, 20, 23.1],
"light": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
"acceleration": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
}
}
}

Version v2.0#

If you select this version for the webhooks then the request body is in the following format.

{
"type":
"operation":
"metadata":{}
"data":{},
}

The timestamp and signature are to be sent in headers, as shown below.

headers:{
"X-Kelvin-Webhook-Signature":signature,
"X-Kelvin-Webhook-Timestamp":timestamp,
}

Device Ping Request Body Format:

{
"type":
"operation":
"metadata":{
"device":{
"type":
"model":
},
"sensors":{
"temperature"
}
},
"data":{
"imei":
"interval":{
"collection":
"transmit":
},
"network":{
"sim": {
"rssi":
}
},
"timestamp":
"battery":
"battery_voltage":
"location": [
{
"hits": ,
"q": {
"waps": [
{
"macAddress":
},
{
"macAddress":
},
{
"macAddress":
}
],
"cts": [
{
"mnc":
"mcc":
"radioType":
"lac":
"cid":
}
]
},
"lng":
"accuracy":
"queriedAt":
"source":
"cachedAt":
"lat":
}
],
"temperature":
"light":
"acceleration":
},
}

Device Ping Request Body Example:

{
"type": "devicePing",
"operation": "create",
"metadata":{
"device":{
"type":"kelvin",
"model":"M300"
},
"sensors":{
"temperature":"INT"
}
},
"data": {
"imei": "30124123",
"interval": {
"collection": 1,
"transmit": 15
},
"network": {
"sim": {
"rssi": 12,
}
},
"timestamp": 1610308993220,
"battery": 92.34,
"battery_voltage": 3121,
"location": [
{
"hits": 1,
"q": {
"waps": [
{
"macAddress": "6c:31:0e:4b:1d:83"
},
{
"macAddress": "3c:51:0e:38:a4:c3"
},
{
"macAddress": "3c:51:0e:38:a4:c2"
}
],
"cts": [
{
"mnc": 1,
"mcc": 505,
"radioType": "lte",
"lac": 36871,
"cid": 17676
}
]
},
"lng": 116.0123039,
"accuracy": 60,
"queriedAt": 1644409702,
"source": "MIX",
"cachedAt": 1644409702,
"lat": -31.9238247
}
],
"temperature": [20.55, 21, 25, 27, 21.7, 20, 23.1],
"light": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
"acceleration": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
}
}

Version v3.0#

This is almost same as v2.0, but we have made additional changes in this by adding the consignment Id and the company Id data in the body.

{
"type":
"operation":
"metadata":{}
"data":{},
}

The timestamp and signature are to be sent in headers, as shown below.

headers:{
"X-Kelvin-Webhook-Signature":signature,
"X-Kelvin-Webhook-Timestamp":timestamp,
}

Device Ping Request Body:

{
"type": "",
"metadata": {
"device": {
"type": "",
"model": ""
},
"sensors": {
"temperature": {
"primarySensor": ""
}
}
},
"operation": "",
"data": {
"uid": "",
"imei": "",
"interval": {
"collection": "",
"transmit": ""
},
"network": {
"sim": {
"rssi": ""
}
},
"timestamp": "",
"battery": "",
"battery_voltage": "",
"location": [
{
"accuracy": "",
"lat": "",
"lng": "",
"source": ""
}
],
"temperature": [],
"light": [],
"acceleration": [],
"humidity": [],
"kind": "",
"eventTypes": [],
"wifiAndCellTowers": [
{
"location_type": "",
"cellTowers": [
{
"csq": "",
"radioType": "",
"mcc": "",
"mnc": "",
"cid": "",
"lac": "",
"bsic": "",
"arfcn": "",
"pci": "",
"rsrp": "",
"rsrq": "",
"rssi": "",
"sinr": "",
"ta": ""
}
]
},
{
"location_type": "",
"wifiAccessPoints": [
{
"signalStrength": "",
"macAddress": ""
}
]
}
],
"secondaryTemperature": [],
"companyId": "",
"consignmentId": ""
}
}

Device Ping Request Body Example:

{
"type": "devicePing",
"metadata": {
"device": {
"type": "kelvin",
"model": "M200|M300"
},
"sensors": {
"temperature": {
"primarySensor": "INT"
}
}
},
"operation": "create",
"data": {
"uid": "f412fa58f42c",
"imei": "f412fa58f42c",
"interval": {
"collection": 10,
"transmit": 60
},
"network": {
"sim": {
"rssi": 23
}
},
"timestamp": 1699959056,
"battery": 59.59,
"battery_voltage": 3781,
"location": [
{
"accuracy": 2309.182176031046,
"lat": 17.441537714443793,
"lng": 78.38298556354903,
"source": "MIX"
}
],
"temperature": [], // This key can be empty if the kind is EVENT or if the sensors are disabled.
"light": [], // This key can be empty if the kind is EVENT or if the sensors are disabled.
"acceleration": [], // This key can be empty if the kind is EVENT or if the sensors are disabled.
"humidity": [], // This key can be empty if the kind is EVENT or if the sensors are disabled.
"kind": "EVENT",
"eventTypes": [
"buttonPress"
],
"wifiAndCellTowers": [
{
"location_type": "CELL",
"cellTowers": [
{
"csq": 23,
"radioType": "gsm",
"mcc": 404,
"mnc": 49,
"cid": 48273,
"lac": 20271,
"bsic": 39,
"arfcn": 29,
"pci": 0,
"rsrp": 0,
"rsrq": 0,
"rssi": 0,
"sinr": 0,
"ta": 2
}
]
},
{
"location_type": "WIFI",
"wifiAccessPoints": [
{
"signalStrength": -56,
"macAddress": "44:95:3B:56:8D:80"
},
{
"signalStrength": -64,
"macAddress": "60:A4:B7:1E:1E:9E"
},
{
"signalStrength": -65,
"macAddress": "60:A4:B7:04:4D:01"
},
{
"signalStrength": -65,
"macAddress": "EC:A2:A0:D8:55:89"
},
{
"signalStrength": -66,
"macAddress": "00:04:95:E7:DD:89"
},
{
"signalStrength": -68,
"macAddress": "90:9A:4A:2B:8A:EB"
},
{
"signalStrength": -76,
"macAddress": "EC:A2:A0:55:06:39"
},
{
"signalStrength": -78,
"macAddress": "78:98:E8:38:4B:9C"
},
{
"signalStrength": -79,
"macAddress": "BC:22:28:29:C7:69"
},
{
"signalStrength": -82,
"macAddress": "B4:A7:C6:00:17:E1"
}
]
}
],
"secondaryTemperature": [], // This key is present only if the device has secondary sensor.
"companyId": "Atreides",
"consignmentId": "Test Consignment" // This key is present if the device is paired with a consignment.
}
}

Verfiying the request source.#

Once the webhooks public and private keys are successfully generated, request body will be posted to the endpoint URL that is saved. From your end, once the request is received, it can be checked for the authentic source using the public key generated in the ‘Create Integration step’. Kelvin uses Elliptic Curve Digital Signature Algorithm for digitally signing the payload. Specifically, we use the starkbank-ecdsa library. You can use the same library (has implementations in Go, Java) to verify the data source. You can find the libraries at https://github.com/starkbank
Request verification example can be found at https://www.npmjs.com/package/starkbank-ecdsa

FAQs#

There are two kinds of pings. One is DATA and other is EVENT. Below are the FAQs about the kind parameter

When do we get KIND: 'DATA' ?
Ans :- KIND: 'DATA' is the default KIND that a person using web-hook can expect, KIND:'DATA' would always mean that there are no events in the forwarded ping and it may or may not have temperature data.

When to expect KIND: 'EVENT'?
Ans :- KIND:"EVENT" is only being sent when the forwarded web-hook ping has "eventTypes" array and that array has any of these values or combination of these values buttonPress

  • lightViolation
  • shockViolation
  • temperatureViolationHigh
  • temperatureViolationLow
  • batteryViolation
  • tripStarted
  • tripEnded - in case of offline trip - will be added in future.
  • charging
  • chargingFull

Is there a possibility that you have KIND:'DATA' and temperature is not present?
Ans:- Yes, the probe sensor might not be working/or might not be connected, in that case there would be an empty temperature array and the KIND is still 'DATA'.

Is there a possibility that you have KIND:'DATA' and has eventTypes present in eventType array?
Ans:- There might be charging related events present in the DATA ping.

Is there a possibility that you have KIND:'EVENT' and empty eventType array?
Ans:- There are different events that might occur on device side that user might not need and used for debugging for internal purposes, so we don't forward the event but the KIND: 'EVENT' might be present. So there would be no temperature data. The above ping is of kind 'EVENT' and the same metadata would be sent in 'DATA' kind ping as well. The sensor values (temperature,light,acceleration) can be empty arrays in the case if the kind is 'EVENT' or if the values are empty or if the sensors are disabled. The secondaryTemperature key will be present only in M300 devices cause only those devices have both Internal and Probe temperature sensors.