Developer Portal
Documentation
API ReferenceConsole

Webhook Guide

Webhooks allow you to get access to a variety of data coming out of your buildings - instead of polling or making inbound requests for the data you need, webhooks send that data directly to you based on a predefined criteria, like what data you want and where you want it to go. Currently webhooks support time series data by point ID, or a subscription to a live query.

Webhooks can be created in two different ways - either using the UI or through the API. We'll walk through the steps on the UI first, and then move into the API calls you can use.

Working with the Webhooks UI

Creating a Webhook

Once you're on the Webhooks page in Tools, you'll initially see a list of the webhooks that already exist. If this is your first time, it'll be a mostly blank page. Up at the top right is a Create Webhook button; clicking that will bring you to the page with the various fields you will need to fill out.

Field NameDescription
NameDescriptive name of the webhook, and should include some indicator of the data being sent
Max Retry CountDetermines how many times we'll try sending the webhook payload to your endpoint before giving up; defaults to 5
MethodDetermines which HTTP Method to use when sending the data; this will typically POST, but you can select from the full list of options
URLThe destination for the webhook payload, like https://www.example.com/mapped_payload
Auth TypeThe type of auth to include with the webhook payload; currently only noAuth and Basic are supported.
Filter TypeJSON Expression used to define what you're subscribing to

JSON Expression can be a bit complex in appearance, but the only pieces you need to worry about are IDs; the rest will always look the same.

A valid filter expression for a time series webhook for an individual point will look like this:

Copy
1
@.source == '//com.mapped/org/ORGUmvDdxfFU7UBvJ8Msx2A6J/timeseries/point/PNTJDa8aQ5LAwfHPn5iGQemwW'

This would be a valid filter expression for a live query subscription:

Copy
1
@.source == '//com.mapped/orgs/ORG8Si1dkzGEYZgxrR4ZYAbCD/liveQueries/LVQAERav1iu5vkp6Qhkmf1234'

The ID listed after orgs will be your org ID (if you're not sure what that is, you can make a call to organization).

In the time series filter expression, the ID listed after /timeseries/point/ is the specific pointId you want time series data from - view the points docs to see how to locate that ID.

In the live query filter expression, the ID after liveQueries is the ID of the specific Live Query you want to subscribe to - view the Live Query docs for an in depth explanation on how to create one, and how to get the ID for it.

Also note the single quotes around the value, after the double equals; without those, the webhook won't work.

Once all the fields are populated, hit the Save button at the bottom right. The webhook will be active from that point forward.

Editing a Webhook

To edit a webhook in the UI, just click on one from the list, make the needed changes, and hit the Save button at the bottom right.

Deleting a Webhook

Similarly, to delete a webhook in the UI, select one from the list and then hit the Delete bottom at the bottom left. You'll be prompted to confirm you really want to delete it; if you click Delete, the webhook will be removed forever.

Creating Webhooks Through the API

Creating a webhook through the API doesn't require making multiple calls - everything is contained within createWebhookTarget. If you drill down into the API Reference a little further, you'll get to WebhookTarget, where the majority of the important fields are located. The critical ones are:

Field NameDescription
contentModeThis field allows you to utilize different structure for the webhook payload; possible values are listed here
enabledDetermines whether the webhook is enabled or not - set it to true or false. Disabled webhooks still exist, but won't send any data to your endpoint
eventFiltersInput the JSON Expression to to define what you want from the webhook (examples shown in previous section of docs)
eventExtensionsThese allow you to assign custom key:value pairs, for use in the target destination for routing or other purposes; supported values are boolean, string and integer
httpTargetProvides all the endpoint details for the webhook, including: targetUri (only HTTP/S URLs are supported currently), the method (such as POST), the auth (currently only noAuth and [Basic][10] are supported) and hmac256 (this is sometimes called a webhook secret - a string value passed with the webhook that can be used to validate the webhook)
maxRetryThis defines how many times to try to send the webhook payload before giving up

The following example creates a webhook linked to a live query with:

  • the ID LVQAERav1iu5vkp6Qhkmf1234
  • inside the org with the ID ORG8Si1dkzGEYZgxrR4ZYAbCd
  • enabled set to true
  • a maxRetry value of 10
  • sending data to the endpoint https://example.com/d123456abcde
  • using a POST
  • with no auth included

Request Response
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
mutation {
    	createWebhookTarget(
    		input: {
    			target: {
    				name: "Live Query Subscription"
    				eventFilters: {
    					jsonExpressionFilter: {
    						jsonPathExpression: "@.source == '//com.mapped/orgs/ORG8Si1dkzGEYZgxrR4ZYAbCD/liveQueries/LVQAERav1iu5vkp6Qhkmf1234'"
    					}
    				}
    				httpTarget: {
    					method: POST
    					targetUri: "https://example..com/d123456abcde"
    					auth: { noAuth: true }
    				}
    				maxRetry: 10
    				enabled: true
    			}
    		}
    	) {
    		target {
    			id
    			name
    			eventFilters {
    				jsonExpressionFilter {
    					jsonPathExpression
    				}
    			}
    			httpTarget {
    				auth {
    					noAuth
    				}
    				method
    				targetUri
    			}
    			maxRetry
    			enabled
    		}
    	}
    }

View Existing Webhooks Through the API

To view the webhooks you've created using the API, you would call webhookTargets. In our example, we'll pull the id, name, the httpTarget information (including the URL and auth) and the eventFilters (which will typically be the JSON Expression defined when the webhook was created):

Request Response
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  webhookTargets {
    id
    name
    httpTarget {
      targetUri
      method
      auth {
        noAuth
      }
    }
    eventFilters {
      jsonExpressionFilter {
        jsonPathExpression
      }
    }
  }
}

Updating Webhooks Through the API

If you wanted to edit a webhook - change the URL, disable or enable it, change the payload's content mode - you would call updateWebhookTarget.

In this example, we'll update the contentMode field; you will also need to include the id field in an updateWebhookTarget call:

Request Response
Copy
1
2
3
4
5
6
7
8
9
10
11
mutation {
  updateWebhookTarget(
    input: {target: {id: "WHSUB5nS9Ng7P2NCWZgT551aiCG", contentMode: {value: STRUCTURED}}}
  ) {
    target {
      id
      name
      contentMode
    }
  }
}

Deleting Webhooks Through the API

To delete a webhook, call deleteWebhookTarget and just pass the ID of the webhook you want removed.

Request Response
Copy
1
2
3
4
5
mutation {
	deleteWebhookTarget(input: { id: "WHSUBMgoLD3fHY329pKANvdAb12" }) {
		_
	}
}

Webhook Payload Examples

The payload for a webhook will vary depending on whether it's for a live query or for time series data. If the webhook is tied to a live query, the results will also vary based on what the live query is tracking, since it could be watching for changes in places, things or points.

Whenever the live query reflects a change value for the assigned query, such as a new site being added to your org, it will trigger the webhook. The response will be formatted as JSON, and will include the live query ID as well for correlation if you have more than one live query running to the same webhook endpoint:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "lastResult": {
    "sites": [
      {
        "id": "SITEA2yCZ58ZpJsE7hH3Sj52CP",
        "name": "OG Site"
      },
      {
        "id": "SITETeZNmbxTZKbN6ArdANbyvX",
        "name": "New Site"
      },
      {
        "id": "SITEK8qWoMJddAgv9SCwJtoYfx",
        "name": "New New Site"
      }
    ]
  },
  "liveQueryId": "LVQCJcMTCrz86gs8UteKroy34"
}

Time series webhooks will be triggered whenever new time series data is detected for the defined pointId(s); the payload will look similar to this:

Copy
1
2
3
4
5
{
  "pointId": "PNTJDa8aQ5LAwfHPn5iGQemwW",
  "timestamp": "2023-10-16T17:44:42.83269Z",
  "value": 100
}

If you defined multiple pointIDs for a single time series webhook, you'll get individual calls for each result - they won't be grouped together. You can determine which value is for which point using the pointId field in the JSON response.

You can also modify the payload using the contentMode field. The example payloads above are with the contentMode undefined, if you set the contentMode to STRUCTURED, the payload would contain the header information, timestamp information and other details like eventExtensions (the values like myint, mystring and mybool below):

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "specversion": "1.0",
  "id": "bfc542e4-bf7e-4917-b4ee-f6b144e81aaa",
  "source": "//com.mapped/org/ORGFEdBM93rarcXPD3hjMHxnD/timeseries/point/PNTDvmfigSEemZWpdCWatABcd",
  "type": "com.mapped.timeseries.point.record.v1",
  "datacontenttype": "application/json",
  "time": "2023-11-09T17:08:59.818217392Z",
  "data": {
    "pointId": "PNTDvmfigSEemZWpdCWatABcd",
    "timestamp": "2023-11-09T17:23:54.111069Z",
    "value": 0
  },
  "myint": 1234,
  "mystring": "hello world",
  "orgid": "ORGFEdBM93rarcXPD3hjMAbcD",
  "traceid": "7459950403562181516",
  "span": "cl6h4b21k0qc73e2hlsg",
  "mybool": true,
  "spanparent": "cl6h4aolhvcc73f79cq0",
  "correlationid": "cl6h4aolhvcc73f79cpg"
}