Build dashboards with the API
Everything you do with dashboards in the control panel goes through the REST API, so you can script it too: create a dashboard, fill it with widgets, place them on the grid and copy it to other accounts. This page shows how, and ends with a reference for every widget type.
For what each widget looks like and how people use it, see the dashboard user guide. For every field and status code, see the Dashboards section in Swagger.
Before you start
Get a token as described in Accessing the API and send it on every call. The examples below use these variables:
export YGGIO_URL="staging.yggio.net"
export YGGIO_TOKEN=$(curl -sS -X POST "https://$YGGIO_URL/api/auth/local" \
-H "Content-Type: application/json" \
-d '{"username":"USER","password":"PASS"}' | jq -r .token)
Endpoints
All paths start with https://staging.yggio.net/api.
| Operation | Request | Success |
|---|---|---|
| List your dashboards | GET /dashboards | 200, array with full widgets |
| One dashboard | GET /dashboards/{dashboardId} | 200, with full widgets |
| Create (or import) a dashboard | POST /dashboards | 201 |
| Update name, header or layout | PATCH /dashboards/{dashboardId} | 200 |
| Duplicate a dashboard | POST /dashboards/{dashboardId}/duplicate | 201 |
| Delete a dashboard and its widgets | DELETE /dashboards/{dashboardId} | 204 |
| Add a widget | POST /dashboards/{dashboardId}/widgets | 201, the new widget |
| Update a widget's settings | PUT /dashboards/{dashboardId}/widgets/{widgetId} | 201, no body |
| Duplicate a widget | POST /dashboards/{dashboardId}/widgets/{widgetId}/duplicate | 201 |
| Delete a widget | DELETE /dashboards/{dashboardId}/widgets/{widgetId} | 204 |
There is no endpoint that reads or writes a single widget on its own. A widget always belongs to one dashboard, and you reach it through that dashboard.
Roles and access rights
Two checks run on every call.
Your role decides which HTTP methods you may use on the dashboard resource. See
Roles.
| Role | What it allows on dashboards |
|---|---|
| Admin | Everything |
| Editor | GET, PATCH, PUT. That is reading, moving and resizing widgets, editing settings and the header. Not creating, duplicating or deleting, because those use POST and DELETE |
| Installer, Viewer Basic, Viewer Standard, Viewer Full | GET only |
| Custom role | The methods the role lists for Dashboard |
A method your role does not allow gives 403 with the body Forbidden.
Your access rights decide which dashboards you can reach. You need read access to see a
dashboard and write access to change it, add or remove widgets, duplicate it or delete it. A
dashboard you cannot see gives 404. One you can see but not write gives 403. When you create a
dashboard you get full access to it. Share it like any other resource, see
Access rights.
Sharing a dashboard does not share the devices on it. A widget shows nothing for a device the viewer has no access to.
The dashboard object
{
"_id": "66f1c0ffee0000000000d001",
"name": "Building A",
"title": "Building A, floor 2",
"description": "Indoor climate and occupancy",
"headerSettings": {"titleFontSize": 32, "align": "left"},
"widgets": [
{
"_id": "66f1c0ffee0000000000a001",
"x": 0, "y": 0, "width": 3, "height": 4,
"template": "deviceValue",
"settings": {"deviceId": "...", "field": "temperature", "...": "..."}
}
]
}
| Field | Rules |
|---|---|
name | Required, at most 50 characters. Shown in the dashboard picker |
title | Optional, at most 100 characters. The header text on the dashboard |
description | Optional, at most 200 characters. The subheader text |
headerSettings | Optional, see below |
widgets | The widgets with their place on the grid |
headerSettings holds the style of the header. All fields are optional:
| Field | Type |
|---|---|
titleFontSize | Number, 10 to 72 |
titleFontWeight | String |
titleColor | String, at most 50 characters |
descriptionFontSize | Number, 8 to 36 |
descriptionColor | String, at most 50 characters |
fontFamily | String, at most 100 characters |
align | left, center or right |
Widgets and the grid
A widget has two parts:
- Where it is.
x,y,widthandheightare stored on the dashboard. - What it is.
template(the widget type) andsettingsare stored in the widget itself.
GET joins the two, so each widget in the response has all six fields plus its _id. Responses
from POST and PATCH on the dashboard list only the place on the grid (_id, x, y, width,
height).
The control panel draws the grid 24 columns wide, with rows 25 px high and 10 px between widgets.
x and width count columns, y and height count rows, and x: 0, y: 0 is the top left. Keep
x + width at 24 or less. The grid packs widgets upwards, so a gap above a widget closes when the
dashboard is shown.
Each widget type has a smallest size in the control panel. A smaller size is saved, but the grid grows the widget to its minimum when you edit the layout. The sizes are in the widget reference.
Create a dashboard
Only name is required.
curl -sS -X POST "https://$YGGIO_URL/api/dashboards" \
-H "Authorization: Bearer $YGGIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Building A", "title": "Building A, floor 2"}'
The response is the new dashboard with its _id.
Create a dashboard with its widgets (import)
POST /dashboards also takes a widgets array. Each entry has x, y, width, height,
template and settings, and no _id. Every widget is created and placed in one call.
{
"name": "Building A",
"widgets": [
{
"x": 0, "y": 0, "width": 7, "height": 2,
"template": "text",
"settings": {"text": "Floor 2", "alignment": "left", "color": "#000000",
"fontSize": "xl", "decoration": "none"}
},
{
"x": 0, "y": 2, "width": 3, "height": 4,
"template": "resourceCount",
"settings": {"resource": "devices"}
}
]
}
This is how Import dashboard works in the control panel. The export string from Export dashboard is
the GET response for that dashboard, as JSON encoded in base64. Decode it and send it to
POST /dashboards to copy a dashboard to another account. The _id fields in it are ignored.
Two things to check first:
- Device, image, rule and dashboard ids in the settings are copied as they are. In another account they usually point to nothing, so update them before you import, or fix the widgets afterwards.
- A widget marked
_broken(see Broken widgets) does not pass the check and stops the whole import. Remove it or fix its settings first.
Add a widget
Send width, height, template and settings. The API puts the widget at x: 0, y: 99, which
means at the bottom of the dashboard, under the others.
curl -sS -X POST "https://$YGGIO_URL/api/dashboards/$DASHBOARD_ID/widgets" \
-H "Authorization: Bearer $YGGIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"width": 3, "height": 4,
"template": "deviceValue",
"settings": {
"deviceId": "'"$DEVICE_ID"'", "field": "temperature",
"display": "text", "color": "blue",
"shouldShowHeading": true, "shouldShowSubheading": false
}
}'
The response is the stored widget, {"_id": ..., "template": ..., "settings": ...}, with every
default filled in. To place it somewhere else, move it.
Update a widget's settings
PUT replaces the whole widget: send template and the complete settings object, not only the
fields you change. A field you leave out goes back to its default, or the call fails if it is
required. The easiest way is to take the widget from GET, change it and send it back.
curl -sS -X PUT "https://$YGGIO_URL/api/dashboards/$DASHBOARD_ID/widgets/$WIDGET_ID" \
-H "Authorization: Bearer $YGGIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "resourceCount", "settings": {"resource": "locations"}}'
templatemust be the same as before. Changing it gives403 Cannot change widget template. To change the type, delete the widget and add a new one.x,y,widthandheightare not read here. UsePATCHon the dashboard.- The response is
201with an empty body. Read the dashboard again to see the result.
Move and resize widgets
The layout lives on the dashboard. Send PATCH /dashboards/{dashboardId} with a widgets array
that lists every widget on the dashboard, each with _id, x, y, width and height. This
is what the control panel sends when you press Save in edit mode.
curl -sS -X PATCH "https://$YGGIO_URL/api/dashboards/$DASHBOARD_ID" \
-H "Authorization: Bearer $YGGIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"widgets": [
{"_id": "66f1c0ffee0000000000a001", "x": 0, "y": 0, "width": 6, "height": 4},
{"_id": "66f1c0ffee0000000000a002", "x": 6, "y": 0, "width": 18, "height": 14}
]
}'
- If the number of widgets does not match the dashboard, the call fails with
422 All existing widgets must be provided. An_idthat is not on the dashboard gives404. PATCHcannot add or remove widgets. Use the widget endpoints for that.templateandsettingsin this array are ignored.
The same PATCH changes name, title, description and headerSettings. Send only the fields
you change. Any other top-level field gives 422.
{"title": "Building A", "headerSettings": {"align": "center", "titleColor": "#1f2937"}}
Duplicate
| What | Request | Result |
|---|---|---|
| A widget | POST /dashboards/{dashboardId}/widgets/{widgetId}/duplicate | A copy with the same settings and the same size and place, added to the same dashboard. The response holds its _id |
| A dashboard | POST /dashboards/{dashboardId}/duplicate | A new dashboard named <name> (copy), with a copy of every widget in the same layout |
Both need write access to the source dashboard. A duplicated dashboard does not keep title,
description or headerSettings. Set them again with PATCH if you need them.
The widget copy gets the same place as the original, so the grid shows one of them below the
other. Move it with PATCH.
Delete
DELETE /dashboards/{dashboardId}/widgets/{widgetId}removes the widget from the dashboard and deletes it.DELETE /dashboards/{dashboardId}deletes the dashboard, all its widgets and its access rights.
There is no undo for either.
Default dashboard
Set as default dashboard in the control panel is not part of the REST API. The control panel stores
it in its own backend, at /control-panel-v2-backend/default-dashboards, one choice per user. That
service is not in Swagger and can change without notice, so do not build on it. Each user picks their
own default in the control panel.
Broken widgets
GET does not fail when one widget no longer matches the rules for its template, for example a
widget saved by an older version or changed directly in the database. Instead that widget comes back
like this:
{
"_id": "66f1c0ffee0000000000a003",
"x": 0, "y": 6, "width": 8, "height": 8,
"template": "floorPlan",
"settings": {"...": "the stored settings, unchanged"},
"_broken": true,
"error": "settings.name: String must contain at least 1 character(s)"
}
_broken: truemarks the widget.errorsays which settings failed and why.- A widget whose stored data is missing comes back with
template: "unknown"anderror: "Widget not found". - The rest of the dashboard is fine. The control panel shows an error box in place of the widget.
- To repair it,
PUTvalid settings for the same template, or delete the widget. - Remove broken widgets before you send a dashboard back to
POST /dashboards.
Errors
| Status | Typical cause |
|---|---|
401 | Missing, invalid or expired token |
403 | Your role does not allow the method (body Forbidden), no write access to the dashboard, or a changed template |
404 | The dashboard does not exist or you cannot see it, or the widget is not on that dashboard |
422 | The body does not pass the check. The message starts with ERR - and names the first field that failed and why |
Widget reference
One section per widget type. Each lists the settings you must send. Settings with a default can be left out, and the default is stored. The full list of optional settings is in Swagger.
Things that hold for all types:
- Unknown settings fail. Most types reject a setting they do not know with
422.imageandfloorPlandrop unknown settings without an error. - Ids are not checked. The API does not check that a
deviceId,imageId,ruleV2IdortargetDashboardIdexists or that you can reach it. A wrong id is saved, and the widget shows nothing. - Which ids.
deviceIdis the device's_idfromGET /api/iotnodes.fieldis the path to a value on the device, for exampletemperatureorcontextMap.room. For charts,GET /api/iotnodes/{_id}/stats/fieldslists the fields that have history. Images come fromPOST /api/images(see Image). - Colours are strings. The control panel uses colour names such as
blueand hex values such as#2169a8. - Thresholds colour a value by range: a list of
{"value": 25, "color": "red"}, with an optionaloperator(gt,gte,eq,lte,lt) on the types that support it.
| Template | Widget | Needs ids of | Default size (min) |
|---|---|---|---|
deviceValue | Device value | A device | 3 x 4 (3 x 4) |
deviceChart | Device chart | A device | 8 x 8 (4 x 5) |
multiDeviceChart | Multi-device chart | Devices | 18 x 14 (6 x 6) |
multiDeviceValue | Multi-device value | Devices | 8 x 8 (3 x 3) |
dataTable | Data table | Devices | 8 x 12 (6 x 6) |
equalizer | Equalizer | Devices | 6 x 6 (2 x 3) |
swimlane | Swimlane | Devices | 8 x 8 (3 x 3) |
pieChart | Pie chart | Devices | 6 x 8 (3 x 3) |
geomap | Geomap | Devices | 8 x 8 (3 x 3) |
floorPlan | Floor plan | An image, devices | 10 x 12 (6 x 4) |
map | Map | Optional: an image, a map view | 16 x 14 (4 x 3) |
commandButtons | Command buttons | Rules (rule v2) | 4 x 4 (2 x 2) |
navigation | Navigation | A dashboard | 4 x 2 (3 x 2) |
resourceCount | Resource count | None | 4 x 4 (3 x 4) |
logs | Logs | None | 14 x 14 (6 x 6) |
text | Text | None | 7 x 2 (3 x 2) |
image | Image | An image | 6 x 8 (2 x 2) |
Sizes are width x height in grid units.
deviceValue
One current value from one device, as text, a circle, a bar or a gauge. User guide: Device value.
| Required | Values |
|---|---|
deviceId | Device _id |
field | Field path, not empty |
display | text, circle, bar or gauge |
color | Colour |
shouldShowHeading | Boolean |
shouldShowSubheading | Boolean |
Useful optional settings: customHeading, customSubheading, unit, minValue, maxValue,
thresholds, barDirection (horizontal or vertical), showSparkline (default false).
{
"width": 3, "height": 4,
"template": "deviceValue",
"settings": {
"deviceId": "DEVICE_ID", "field": "temperature", "display": "gauge",
"color": "blue", "minValue": 0, "maxValue": 40,
"shouldShowHeading": true, "shouldShowSubheading": false
}
}
deviceChart
One field from one device over time, as a line. User guide: Device chart.
| Required | Values |
|---|---|
deviceId | Device _id |
field | Field path, not empty |
timePeriod | fiftenMinutes, thirtyMinutes, hour, threeHours, sixHours, twelveHours, day, week, month, threeMonths, sixMonths, year or custom |
resolution | full, oneMinute, fiveMinutes, fifteenMinutes, thirtyMinutes, hour, threeHours, sixHours, twelveHours, day, week, month or custom |
curveType | step, linear or monotone |
yAxisRange | auto or fromZero |
calculation | mean, timeWeightedMean, min, max, first, last, count, sum or difference |
shouldShowHeading | Boolean |
shouldShowSubheading | Boolean |
Note the spelling fiftenMinutes for timePeriod. It is the stored value. With timePeriod: custom
set customFromTime and customToTime. With resolution: custom set customResolution.
{
"width": 8, "height": 8,
"template": "deviceChart",
"settings": {
"deviceId": "DEVICE_ID", "field": "temperature",
"timePeriod": "day", "resolution": "hour", "curveType": "monotone",
"yAxisRange": "auto", "calculation": "mean",
"shouldShowHeading": true, "shouldShowSubheading": false
}
}
multiDeviceChart
Several devices and fields on one chart, as lines, bars or stacked bars. User guide: Multi-device chart.
| Required | Values |
|---|---|
deviceFieldPairs | At least one {"deviceId": ..., "field": ...} |
timePeriod, resolution, curveType, yAxisRange, calculation | As for deviceChart |
shouldShowHeading | Boolean |
shouldShowLegend | Boolean |
chartType is line (the default when left out), area, bar or stackedBar.
{
"width": 18, "height": 14,
"template": "multiDeviceChart",
"settings": {
"deviceFieldPairs": [
{"deviceId": "DEVICE_ID_1", "field": "temperature"},
{"deviceId": "DEVICE_ID_2", "field": "temperature"}
],
"timePeriod": "week", "resolution": "day", "curveType": "linear",
"yAxisRange": "auto", "calculation": "mean", "chartType": "bar",
"shouldShowHeading": true, "shouldShowLegend": true
}
}
multiDeviceValue
Current values from several devices in a grid of tiles. User guide: Multi-device value.
| Required | Values |
|---|---|
items | At least one {"deviceId": ..., "field": ...}. Each item can also have label, unit, color and thresholds |
Defaults: columns 3 (1 to 6), colorMode value (or background), shouldShowHeading true.
{
"width": 8, "height": 8,
"template": "multiDeviceValue",
"settings": {
"items": [
{"deviceId": "DEVICE_ID_1", "field": "temperature", "unit": "°C"},
{"deviceId": "DEVICE_ID_2", "field": "humidity", "unit": "%"}
],
"columns": 2
}
}
dataTable
A table with a row per device and a column per field. User guide: Data table.
| Required | Values |
|---|---|
devices | At least one {"deviceId": ..., "fields": [...]}, with at least one field each |
shouldShowHeading | Boolean |
columnConfigs styles a column, keyed by field: field (required, the same as the key), displayName, displayMode (text or
barGauge), thresholds, unit, min, max. showExportButton defaults to true.
{
"width": 8, "height": 12,
"template": "dataTable",
"settings": {
"devices": [
{"deviceId": "DEVICE_ID_1", "fields": ["temperature", "humidity"]},
{"deviceId": "DEVICE_ID_2", "fields": ["temperature", "humidity"]}
],
"shouldShowHeading": true,
"columnConfigs": {"temperature": {"field": "temperature", "displayName": "Temp", "unit": "°C"}}
}
}
equalizer
Current values as vertical bars on one scale. User guide: Equalizer.
| Required | Values |
|---|---|
items | At least one {"deviceId": ..., "field": ...}, same shape as in multiDeviceValue |
minValue and maxValue fix the scale. Leave them out to scale from the current values.
{
"width": 6, "height": 6,
"template": "equalizer",
"settings": {
"items": [
{"deviceId": "DEVICE_ID_1", "field": "passengers", "label": "Train 1"},
{"deviceId": "DEVICE_ID_2", "field": "passengers", "label": "Train 2"}
],
"minValue": 0, "maxValue": 300
}
}
swimlane
Live values streaming across one lane per signal. Nothing is kept after the page closes. User guide: Swimlane.
| Required | Values |
|---|---|
signals | At least one {"deviceId": ..., "field": ...}, each with optional label, unit, color |
windowSeconds is the visible time window, 10 to 3600, default 60.
{
"width": 8, "height": 8,
"template": "swimlane",
"settings": {
"signals": [{"deviceId": "DEVICE_ID", "field": "power", "unit": "W"}],
"windowSeconds": 120
}
}
pieChart
One field across several devices, each slice a device's share of the total. User guide: Pie chart.
| Required | Values |
|---|---|
field | Field path, not empty |
devices | At least one {"deviceId": ...}, each with an optional alias |
{
"width": 6, "height": 8,
"template": "pieChart",
"settings": {
"field": "passengers",
"devices": [{"deviceId": "DEVICE_ID_1", "alias": "Train 1"}, {"deviceId": "DEVICE_ID_2"}]
}
}
geomap
Where devices have been, each with a trail on the map. User guide: Geomap.
| Required | Values |
|---|---|
devices | At least one {"deviceId": ...}, each with an optional alias |
trailLength is the number of points kept per device, 0 to 200, default 20. tileLayer defaults
to street.
{
"width": 8, "height": 8,
"template": "geomap",
"settings": {"devices": [{"deviceId": "DEVICE_ID"}], "trailLength": 50}
}
floorPlan
Device markers placed on a background image. User guide: Floor plan.
| Required | Values |
|---|---|
imageId | Image _id, see Image for how to upload |
name | 1 to 30 characters |
devices | List of {"deviceId": ..., "x": ..., "y": ...}. x and y can be null for a device not yet placed. Can be empty |
deviceValues | List of {"field": ..., "thresholds": [...], "isStarred": ...}, the values shown for each device. Can be empty |
deviceMarkerType | circle, ring, dot, square or seat |
shouldSnapToGrid | Boolean |
gridCellSize | Whole number, 1 or more, or null |
The marker x and y are positions on the image. Placing markers is easier in the control panel:
create the widget with an empty devices list or with null positions, and drag the markers there.
{
"width": 10, "height": 12,
"template": "floorPlan",
"settings": {
"imageId": "IMAGE_ID", "name": "Floor 2",
"devices": [{"deviceId": "DEVICE_ID", "x": null, "y": null}],
"deviceValues": [{"field": "temperature", "thresholds": [], "isStarred": true}],
"deviceMarkerType": "circle",
"shouldSnapToGrid": false, "gridCellSize": null
}
}
map
Devices on a map, with an optional saved map view, overlay image or geofences. User guide: Map.
Nothing is required. {} gives a map of your devices.
| Optional | Values |
|---|---|
viewId | Id of a saved map view. Map views are stored by the control panel, not the REST API, so pick one there |
imageId | Image _id of an overlay image |
createGeofenceEnabled | Boolean |
{"width": 16, "height": 14, "template": "map", "settings": {}}
commandButtons
Buttons that trigger a rule. User guide: Command buttons.
| Required | Values |
|---|---|
buttons | At least one button, each with ruleV2Id, triggerNodeId and label |
ruleV2Idis the rule's_idfromGET /api/rules-v2.triggerNodeIdis theidof a node in that rule'sdefinition.nodeswithtype: "trigger"andconfig.resourceType: "button". Only rules with such a node can be used.- Each button can also have
icon,color(defaultblue),iconOnlyandtextAlign.
Pressing the button calls POST /api/rules-v2/{ruleV2Id}/execute for that trigger.
{
"width": 4, "height": 4,
"template": "commandButtons",
"settings": {
"buttons": [
{"ruleV2Id": "RULE_ID", "triggerNodeId": "TRIGGER_NODE_ID", "label": "Lights on", "color": "green"}
]
}
}
navigation
A button that opens another dashboard. User guide: Navigation.
| Required | Values |
|---|---|
targetDashboardId | _id of the dashboard to open |
Optional: largeText, smallText, icon, buttonStyle (filled, outline or plain),
alignment.
{
"width": 4, "height": 2,
"template": "navigation",
"settings": {"targetDashboardId": "OTHER_DASHBOARD_ID", "largeText": "Floor 3"}
}
resourceCount
How many resources of one kind you have. User guide: Resource count.
| Required | Values |
|---|---|
resource | devices, locations, organizations, apps or rules |
{"width": 4, "height": 4, "template": "resourceCount", "settings": {"resource": "devices"}}
logs
The latest log entries, filtered. User guide: Logs.
Nothing is required. {} shows device logs.
| Optional | Values |
|---|---|
resourceType | device (default), connector, userGroup, organization or ruleV2 |
type | List of error, warning, info, verbose, debug |
priority | List of severe, high, medium, low |
category | update, command, status, access, analytics, rule or system |
timeRange | For example {"start": {"type": "relative", "amount": 24, "unit": "hours"}, "end": {"type": "now"}} |
title | String |
{
"width": 14, "height": 14,
"template": "logs",
"settings": {"type": ["error", "warning"], "priority": ["severe", "high"]}
}
text
Free text. User guide: Text.
| Required | Values |
|---|---|
text | Not empty |
alignment | left, center or right |
color | Colour |
fontSize | xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl or 6xl |
decoration | none, underline, overline or line-through |
Optional with defaults: bold, italic, fontFamily, backgroundColor, verticalAlignment,
opacity (10 to 100).
{
"width": 7, "height": 2,
"template": "text",
"settings": {"text": "Floor 2", "alignment": "left", "color": "#000000",
"fontSize": "2xl", "decoration": "none", "bold": true}
}
image
A picture, such as a logo or a photo. User guide: Image.
| Required | Values |
|---|---|
imageId | Image _id |
imageSize | small, medium or large |
shape | none, rounded or full |
background | no-background or background |
horizontalAlignment | left, center or right |
verticalAlignment | upp, center or low |
Upload the image first. It is a multipart form with the file in image, a name (3 to 256
characters) and a category (widget here, floorPlan for a floor plan, mapOverlay for a map).
The _id in the response is the imageId.
curl -sS -X POST "https://$YGGIO_URL/api/images" \
-H "Authorization: Bearer $YGGIO_TOKEN" \
-F "image=@logo.png" -F "name=company-logo" -F "category=widget"
{
"width": 6, "height": 8,
"template": "image",
"settings": {
"imageId": "IMAGE_ID", "imageSize": "medium", "shape": "none",
"background": "no-background", "horizontalAlignment": "center", "verticalAlignment": "center"
}
}
See also
- Accessing the API - tokens, curl and Postman.
- Dashboards user guide - every widget, with pictures.
- Roles and Access rights.
- Swagger - the full REST API reference.