Getting started

How to get started with Webhooks from Airthings

Webhooks provide a low-effort way to receive event-based data from your Airthings devices.

How it Works

Depending on which event-based data you'd like to receive, you can select specific events - like Hub metadata or device sample feed (see Webhook Event Types for more information), and send it to your endpoint (URL).

The current implementation has the following constraints

  • Fire and forget, there is no retrying currently.
  • Samples are aggregated in batches per serial number.

Setting up a Webhook

To make use of the concept, all that needs to be done is to:

  • Create an endpoint in your API for receiving events from the Airthings Platform.
  • Create a webhook either using the Airthings for Business Dashboard, or through the Airthings for Business API.

Webhooks in the Airthings API

The API has four different endpoints for webhooks which can be used to list all endpoints in the account, add a webhook, edit a webhook or delete a webhook.

POST Webhook

Use POST /webhooks?accountId={{account_id}} with the following example request body:

{
    "name": "My webhook",
    "url": "https://myurl.com",
    "labels": { "key": "value" },
    "headers": { "key": "value" },
    "devices": ["293000000"],
    "locations": ["0aaac9e8-c26b-4141-9177-1105b65736ae"],
    "active": true,
    "eventTypes": ["sample-feed"],
    "sensorUnits": {
      "tempUnit": "c",
      "pressureUnit": "hPa",
      "radonUnit": "bq",
      "vocUnit": "ppb"
    }
}

Response:

{
    "name": "My webhook",
    "url": "https://myurl.com",
    "labels": { "key": "value" },
    "headers": { "key": "value" },
    "locations": [
        {
          "id": "591df93d-ec4e-4780-959c-e8c474e29d7a",
          "name": "Oslo",
          "labels": {}
        }
     ],
    "devices": [
       {
          "id": "293000000",
          "deviceType": "WAVE_PLUS",
          "sensors": [
             "radonShortTermAvg",
             "temp",
             "humidity",
             "pressure",
             "co2",
             "voc",
             "light",
             "virusRisk"
          ],
          "segment": {
             "id": "017dd064-0ccd-4902-825e-32e7960edd73",
             "name": "Device name",
             "started": "2021-06-03T15:18:56",
             "active": true
          }
       }
    ],
    "active": true,
    "eventTypes": [
       "sample-feed"
    ],
    "sensorUnits": {
      "tempUnit": "c",
      "pressureUnit": "hPa",
      "radonUnit": "bq",
      "vocUnit": "ppb"
    }
}

Note that all parameters except name and url are optional. All webhooks are by default set to the METRIC measurement system and set to active - unless specified otherwise.

Furthermore, by default, a webhook is forwarded data for all event types. An event type is used to classify the types of data and their origin. For example, sample-feed is data that comes directly from our devices, such as humidity, temp, and radon values. A full

GET Webhooks

Use GET /webhooks?accountId={{account_id}}

Response:

{
   "webhooks": [{...}]
}

Testing a Webhook in the Dashboard

When the webhook has been created: To verify the function press the "Test Webhook" button. An example event is then forwarded to the URL specified in the form. To test the webhook and evaluate the format before implementing a receiving endpoint you can use a webservice simulating such an endpoint, for example webhook.site, beeceptor.com.

Webhook.site support printing the received payload as formatted JSON.

The events are delivered as JSON based on the CloudEvents standard.

  • It is possible to distinct between test events and real events by looking at the type property.
  • The source attribute refers to the id of the webhook which was utilized in creating the event.

Real event:

{
  "id": "91f7fc45-8006-4279-9b0a-fa8b812020fa",
  "type": "airthings-webhook-cloudevent-sample-feed",
  "source": "accounts.airthings.com/webhooks/17995b45-26e9-47e2-8af7-7267f7d89bc0",
  "dataContentType": "application/json",
  "labels": {},
  "data": [
    {
      "serialNumber": "2930001150",
      "recorded": "2019-10-17T12:20:49",
      "radonShortTermAvg": 14,
      "humidity": 56.5,
      "temp": 29.3,
      "co2": 644,
      "pressure": 1010,
      "tvoc": 112,
      "rssi": -51,
      "batteryPercentage": 100,
      "ratings": {
         "radonShortTermAvg": "GOOD",
         "temp": "POOR",
         "pressure": "GOOD",
         "humidity": "FAIR",
         "voc": "GOOD",
         "co2": "FAIR"
      },
      "sensorUnits": {
        "temp": "c",
        "humidity": "pct",
        "co2": "ppm",
        "voc":"ppb",
        "pressure": "hPa",
        "radonShortTermAvg": "bq"
      }
    }
  ],
  "time": "2019-10-17T12:22:53.650000",
  "specVersion": "0.2"
}

Test event:
Triggered manually from the dashboard.airthings.com/integrations/webhooks details page

{
  "id": "200ded7a-a0c6-44c8-b133-0166c7b5ff62",
  "type": "airthings-webhook-cloudevent-sample-manually-triggered-test",
  "source": "accounts.airthings.com/webhooks/e0746daf-aabf-4aea-b4ab-814fe889d6a7",
  "dataContentType": "application/json",
  "labels": {},
  "data": [
    {
      "recorded": "2019-10-15T09:42:45",
      "serialNumber": "2930000948",
      "radonShortTermAvg": 0,
      "temp": 0,
      "co2": 0,
      "pressure": 0,
      "tvoc": 0
    }
  ],
  "time": "2019-10-15T09:42:45.058000",
  "specVersion": "0.2"
}

Event with multiple samples:
A set of samples aggregated into one event (if they arrive in the same samples batch)

{
  "id": "91f7fc45-8006-4279-9b0a-fa8b812020fa",
  "type": "airthings-webhook-cloudevent-sample-feed",
  "source": "accounts.airthings.com/webhooks/17995b45-26e9-47e2-8af7-7267f7d89bc0",
  "dataContentType": "application/json",
  "labels": {},
  "data": [
    {
      "serialNumber": "2930001150",
      "recorded": "2019-10-17T12:20:49",
      "radonShortTermAvg": 14,
      "humidity": 56.5,
      "temp": 22.3,
      "co2": 644,
      "pressure": 1010,
      "tvoc": 112,
      "rssi": -51,
      "batteryPercentage": 99,
      "ratings": {
          "radonShortTermAvg": "GOOD",
          "temp": "POOR",
          "pressure": "GOOD",
          "humidity": "FAIR",
          "voc": "GOOD",
          "co2": "FAIR"
      },
      "sensorUnits": {
        "temp": "c",
        "humidity": "pct",
        "co2": "ppm",
        "voc":"ppb",
        "pressure": "hPa",
        "radonShortTermAvg": "bq"
      }
    },
    {
      "serialNumber": "2930001151",
      "recorded": "2019-10-17T12:20:47",
      "radonShortTermAvg": 10,
      "humidity": 55.5,
      "temp": 21.3,
      "co2": 654,
      "pressure": 1010,
      "tvoc": 310,
      "rssi": -59,
      "batteryPercentage": 89,
      "ratings": {
          "radonShortTermAvg": "GOOD",
          "temp": "POOR",
          "pressure": "GOOD",
          "humidity": "FAIR",
          "voc": "GOOD",
          "co2": "FAIR"
      },
      "sensorUnits": {
        "temp": "c",
        "humidity": "pct",
        "co2": "ppm",
        "voc":"ppb",
        "pressure": "hPa",
        "radonShortTermAvg": "bq"
      }
    }   
  ],
  "time": "2019-10-17T12:22:53.650000",
  "specVersion": "0.2"
}