Docs

Webhooks

What are webhooks?

Outgoing Webhooks allow SenseCore to automatically send real-time data updates from your devices to your own systems or applications.
Each client is provided with a unique webhook URL. SenseCore configures all required settings on your behalf and begins transmitting data as soon as your workspace is active.

How It Works

When new sensor data or event notifications are generated on the SenseCore platform, our system sends an HTTPS POST request containing a JSON payload to your assigned webhook URL.

Example flow:

  1. SenseCore configures and activates your webhook.

  2. Your devices send data to the SenseCore platform.

  3. SenseCore forwards the data in JSON format to your webhook endpoint.

  4. Your application receives and processes the data in real time.

Use cases

Sync device measurements to your system

You can create a webhook that listens to “measurement recorded” events and stores them in your external database.

Act on raw data from payload decoders

Sometimes, payload decoders return more data than is stored in the time-series database. You can use webhooks to trigger actions based on this information, without paying for storage.

Decoder Output (Payload Decoder)

This is the raw output from a device payload decoder as can also be seen in a device debug view, including:

  • Decoder returned data

  • Console Log

  • Device Information (LoRaWAN or Particle device types)

    An example output looks like the following:

				
					{
  "data": {
    "log": null,
    "device": null,
    "result": [
      {
        "field": "TOWER_LOCATION",
        "value": "(34.492523,136.171631)",
        "device": "dev:864475044240892"
      },
      {
        "field": "DEVICE_LOCATION",
        "value": "(34.4823475,136.16275390624997)",
        "device": "dev:864475044240892"
      },
      {
        "field": "RSSI",
        "device": "dev:864475044240892"
      },
      {
        "field": "BARS",
        "device": "dev:864475044240892"
      },
      {
        "field": "VOLTAGE",
        "device": "dev:864475044240892"
      },
      {
        "field": "CARD_TEMPERATURE",
        "device": "dev:864475044240892"
      },
      {
        "field": "ORIENTATION",
        "device": "dev:864475044240892"
      },
      {
        "field": "PM1",
        "value": 3.4,
        "device": "dev:864475044240892"
      },
      {
        "field": "PM25",
        "value": 4.88,
        "device": "dev:864475044240892"
      },
      {
        "field": "PM10",
        "value": 4.88,
        "device": "dev:864475044240892"
      },
      {
        "field": "TEMPERATURE",
        "value": 10.616931,
        "device": "dev:864475044240892"
      },
      {
        "field": "PRESSURE",
        "value": 95909.72,
        "device": "dev:864475044240892"
      },
      {
        "field": "HUMIDITY",
        "value": 59.889774,
        "device": "dev:864475044240892"
      }
    ],
    "product": "ef6275c7-3e9b-4134-9bef-24bc276a9592",
    "execution_time": 664535
  },
  "event": "decoder_output"
}
				
			

Decoder Output (Device measurements)

This event type is triggered only on new measurement values recorded on the database. This does not necessarily contain all the data of all fields on a device as it only holds the fields that are being inserted on the last message received by your device.

The webhook data would look like the following:

				
					{
  "data": [
    {
      "field": "TOWER_LOCATION",
      "value": "(26.2319375,-81.742609375)",
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852979
    },
    {
      "field": "DEVICE_LOCATION",
      "value": "(26.237302500000006,-81.74094921875)",
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852979
    },
    {
      "field": "ORIENTATION",
      "value": "",
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852980
    },
    {
      "field": "PM1",
      "value": 0.14084508,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852980
    },
    {
      "field": "PM10",
      "value": 0.8309859,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852981
    },
    {
      "field": "TEMPERATURE",
      "value": 19.141228,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852981
    },
    {
      "field": "PRESSURE",
      "value": 102081.35,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852981
    },
    {
      "field": "HUMIDITY",
      "value": 66.95572,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852981
    },
    {
      "field": "PM25",
      "value": 0.28169015,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852980
    },
    {
      "field": "TOWER_LOCATION",
      "value": "(26.2319375,-81.742609375)",
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852984
    },
    {
      "field": "DEVICE_LOCATION",
      "value": "(26.237302500000006,-81.74094921875)",
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852984
    },
    {
      "field": "ORIENTATION",
      "value": "",
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852986
    },
    {
      "field": "PM25",
      "value": 0.16901408,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852986
    },
    {
      "field": "PM10",
      "value": 0.5492958,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852986
    },
    {
      "field": "TEMPERATURE",
      "value": 19.0143,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852986
    },
    {
      "field": "PRESSURE",
      "value": 102088.086,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852986
    },
    {
      "field": "HUMIDITY",
      "value": 66.58315,
      "device": "f7384fd1-9e7f-4540-b4ed-5fa5810bcc27",
      "timestamp": 1647852987
    }
  ],
  "event": "device_measurement"
}
				
			
Troubleshooting

The list of webhooks contains useful debugging information, such as a chart of the number of requests in the last seven days and the error rate.

Click on one of your webhooks to see a list of the last requests as well as the response from your server.

SenseCore GraphQL API

Overview

The SenseCore GraphQL API allows you to query, manage, and interact with your workspaces, devices, and telemetry data through a single unified endpoint.
It provides developers with a flexible and efficient way to access and integrate data directly into custom dashboards, third-party systems, or analytics tools.

Generate  Access Token

An API token is issued for each specific deployment or workspace. To obtain one, please contact support@sensecore.ca

Note that access tokens give access to your account! Store them securely and do not share them with anyone.

You then have to pass this personal access token in the Authorization header as a token:

				
					Authorization: Token <YOUR_TOKEN_HERE>
				
			

Browse Documentation

For now, the only documentation for the API is exploring the schema with the GraphiQL at https://dashboard.sensecore.ca/api/graphql(click the “Docs” button on the upper right edge).

Authentication

To authenticate in GraphiQL, paste your API token in the corresponding field at the top of the page:

If you do not authorize correctly, your request will be treated as unauthenticated. The easiest way to check if you are authorized is to query for the authenticated user data:

				
					query {
    user {
        id
    }
}
				
			

If the returned user object is null, the request is not authenticated.

If you have any specific questions on how to achieve certain tasks, feel free to ping us directly at support@sensecore.ca, we would be happy to help!

Overview

In this tutorial we will show you how you can use the powerful GraphQL API to access historical and current device data with SenseCore.

HTTP

You can use a cURL Command to call the GraphQL Library directly.

				
					curl \
-X GET \
-H "Content-Type: application/json" \
-H "Authorization: Token 1234567yourtoken1234567" \
--data '{"query": "query { allDevices(inWorkspace:\"dc578994-your-workspace-84221d0\") { currentMeasurements(allActiveFields: true) { value field { verboseFieldName fieldName } } } }"}' \
https://dashboard.sensecore.ca/api/graphql/
				
			

Workspaces

List of Workspaces

				
					query {
  allWorkspaces {
    id
    name
  }
}
				
			

List Of Devices

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    id
    verboseName
  }
}
				
			

Current  Measurements

All Devices in Workspace

You can use the currentMeasurements option to have all the last recorded measurements of one or more devices returned.

Use the allActiveFields option as follows to return only those fields that are active in the database.

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurements(allActiveFields: true) {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
				
			

Specific Fields only

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurements(fieldNames:["BATTERY"]) {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
				
			

Specific Fields only

Instead of providing an Array of Field Identifiers you can use the currentMeasurement Option to Query a specific field only.

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurement(fieldName:"BATTERY") {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
				
			

Specific Device

The above examples are using the allDevices Option to query all devices in a given Workspace. If you just want to access data from a specific device only, you can use the device Option.

				
					device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a")
				
			

Use this as in the following example query:

				
					query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    currentMeasurements(allActiveFields: true) {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
				
			

Specific Device

If your fields in database store a String-type value you have to add the valueString option to return the corresponding value.

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurements(allActiveFields: true) {
      valueString
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
				
			

Working with Maximum, Average

				
					maximum(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
average(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
change(average(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
				
			
				
					query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    currentMeasurements(allActiveFields: true) {
      value
      maximum(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
				
			

So will look like

				
					{
  "data": {
    "device": {
      "currentMeasurements": [
        {
          "value": 3.067,
          "average": 3.06697222222223,
          "maximum": 3.069,
          "change": 0,
          "modified": "2021-04-17T12:58:30.554976+00:00",
          "field": {
            "verboseFieldName": "Battery",
            "fieldName": "BATTERY"
          }
        }
      ]
    }
  }
}
				
			

Historical Data

From all Devices in Workspace

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    history(
      fields:["BATTERY"], 
      timerangestart:"2021-04-16T00:00", 
      timerangeend:"2021-04-17T00:00", 
      resolution:"120m"
    )
  }
}
				
			
  • fields: Set of fields, has to be identifier of database field.

  • timerangestart: Starting of time frame, has to be before timerangeend.

  • timerangeend: End of time frame, should never be in the future.

  • resultion: Quantisation-Factor, see below.

From a Specific Device

				
					query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(fields:["BATTERY"], timerangestart:"2021-04-16T00:00", timerangeend:"2021-04-17T00:00", resolution:"raw") 
  }
}
				
			

Fields have to be Identifier:

				
					fields:["BATTERY"]
				
			

Multiple Fields

				
					query {
  device(deviceId:"702d77a7-a292-476a-a546-d5dde80e6f5d") {
    history(fields:["HUM_SHT", "TEMPC_SHT"], timerangestart:"2023-12-16T00:00", timerangeend:"2023-12-17T00:00", resolution:"30 minutes") 
  }
}
				
			

Working with Resolution

One of the options for the history settings is an option called resolution. This gives you two options:

  • raw – Raw Data Export. Data will be exported as stored in the database

  • X minutes – Quantisation in X Minutes – Data will be combined into timerange-chunks of given value.

  • Other valid values are: X hours

 

The operation for quantisation is an average. You cannot change this right now.

Working with Resolution

				
					query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(
      fields:["BATTERY"], 
      timerangestart:"2021-04-16T00:00", 
      timerangeend:"2021-04-17T00:00", 
      resolution:"raw"
      ) 
  }
}
				
			

Quantisation

				
					query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(
      fields:["BATTERY"], 
      timerangestart:"2021-04-16T00:00", 
      timerangeend:"2021-04-17T00:00", 
      resolution:"20m"
      ) 
  }
}
				
			

Devices

Metadata

The following snippet works for both allDevices and specific device Options.

				
					query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    location
    lastHeard
    claimed
    claimCode
    tags
    serialNumber
  }
}