Skip to main content

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.

OperationRequestSuccess
List your dashboardsGET /dashboards200, array with full widgets
One dashboardGET /dashboards/{dashboardId}200, with full widgets
Create (or import) a dashboardPOST /dashboards201
Update name, header or layoutPATCH /dashboards/{dashboardId}200
Duplicate a dashboardPOST /dashboards/{dashboardId}/duplicate201
Delete a dashboard and its widgetsDELETE /dashboards/{dashboardId}204
Add a widgetPOST /dashboards/{dashboardId}/widgets201, the new widget
Update a widget's settingsPUT /dashboards/{dashboardId}/widgets/{widgetId}201, no body
Duplicate a widgetPOST /dashboards/{dashboardId}/widgets/{widgetId}/duplicate201
Delete a widgetDELETE /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.

RoleWhat it allows on dashboards
AdminEverything
EditorGET, 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 FullGET only
Custom roleThe 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", "...": "..."}
}
]
}
FieldRules
nameRequired, at most 50 characters. Shown in the dashboard picker
titleOptional, at most 100 characters. The header text on the dashboard
descriptionOptional, at most 200 characters. The subheader text
headerSettingsOptional, see below
widgetsThe widgets with their place on the grid

headerSettings holds the style of the header. All fields are optional:

FieldType
titleFontSizeNumber, 10 to 72
titleFontWeightString
titleColorString, at most 50 characters
descriptionFontSizeNumber, 8 to 36
descriptionColorString, at most 50 characters
fontFamilyString, at most 100 characters
alignleft, center or right

Widgets and the grid​

A widget has two parts:

  • Where it is. x, y, width and height are stored on the dashboard.
  • What it is. template (the widget type) and settings are 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"}}'
  • template must be the same as before. Changing it gives 403 Cannot change widget template. To change the type, delete the widget and add a new one.
  • x, y, width and height are not read here. Use PATCH on the dashboard.
  • The response is 201 with 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 _id that is not on the dashboard gives 404.
  • PATCH cannot add or remove widgets. Use the widget endpoints for that.
  • template and settings in 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​

WhatRequestResult
A widgetPOST /dashboards/{dashboardId}/widgets/{widgetId}/duplicateA copy with the same settings and the same size and place, added to the same dashboard. The response holds its _id
A dashboardPOST /dashboards/{dashboardId}/duplicateA 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: true marks the widget. error says which settings failed and why.
  • A widget whose stored data is missing comes back with template: "unknown" and error: "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, PUT valid settings for the same template, or delete the widget.
  • Remove broken widgets before you send a dashboard back to POST /dashboards.

Errors​

StatusTypical cause
401Missing, invalid or expired token
403Your role does not allow the method (body Forbidden), no write access to the dashboard, or a changed template
404The dashboard does not exist or you cannot see it, or the widget is not on that dashboard
422The 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. image and floorPlan drop unknown settings without an error.
  • Ids are not checked. The API does not check that a deviceId, imageId, ruleV2Id or targetDashboardId exists or that you can reach it. A wrong id is saved, and the widget shows nothing.
  • Which ids. deviceId is the device's _id from GET /api/iotnodes. field is the path to a value on the device, for example temperature or contextMap.room. For charts, GET /api/iotnodes/{_id}/stats/fields lists the fields that have history. Images come from POST /api/images (see Image).
  • Colours are strings. The control panel uses colour names such as blue and hex values such as #2169a8.
  • Thresholds colour a value by range: a list of {"value": 25, "color": "red"}, with an optional operator (gt, gte, eq, lte, lt) on the types that support it.
TemplateWidgetNeeds ids ofDefault size (min)
deviceValueDevice valueA device3 x 4 (3 x 4)
deviceChartDevice chartA device8 x 8 (4 x 5)
multiDeviceChartMulti-device chartDevices18 x 14 (6 x 6)
multiDeviceValueMulti-device valueDevices8 x 8 (3 x 3)
dataTableData tableDevices8 x 12 (6 x 6)
equalizerEqualizerDevices6 x 6 (2 x 3)
swimlaneSwimlaneDevices8 x 8 (3 x 3)
pieChartPie chartDevices6 x 8 (3 x 3)
geomapGeomapDevices8 x 8 (3 x 3)
floorPlanFloor planAn image, devices10 x 12 (6 x 4)
mapMapOptional: an image, a map view16 x 14 (4 x 3)
commandButtonsCommand buttonsRules (rule v2)4 x 4 (2 x 2)
navigationNavigationA dashboard4 x 2 (3 x 2)
resourceCountResource countNone4 x 4 (3 x 4)
logsLogsNone14 x 14 (6 x 6)
textTextNone7 x 2 (3 x 2)
imageImageAn image6 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.

RequiredValues
deviceIdDevice _id
fieldField path, not empty
displaytext, circle, bar or gauge
colorColour
shouldShowHeadingBoolean
shouldShowSubheadingBoolean

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.

RequiredValues
deviceIdDevice _id
fieldField path, not empty
timePeriodfiftenMinutes, thirtyMinutes, hour, threeHours, sixHours, twelveHours, day, week, month, threeMonths, sixMonths, year or custom
resolutionfull, oneMinute, fiveMinutes, fifteenMinutes, thirtyMinutes, hour, threeHours, sixHours, twelveHours, day, week, month or custom
curveTypestep, linear or monotone
yAxisRangeauto or fromZero
calculationmean, timeWeightedMean, min, max, first, last, count, sum or difference
shouldShowHeadingBoolean
shouldShowSubheadingBoolean

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.

RequiredValues
deviceFieldPairsAt least one {"deviceId": ..., "field": ...}
timePeriod, resolution, curveType, yAxisRange, calculationAs for deviceChart
shouldShowHeadingBoolean
shouldShowLegendBoolean

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.

RequiredValues
itemsAt 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.

RequiredValues
devicesAt least one {"deviceId": ..., "fields": [...]}, with at least one field each
shouldShowHeadingBoolean

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.

RequiredValues
itemsAt 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.

RequiredValues
signalsAt 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.

RequiredValues
fieldField path, not empty
devicesAt 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.

RequiredValues
devicesAt 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.

RequiredValues
imageIdImage _id, see Image for how to upload
name1 to 30 characters
devicesList of {"deviceId": ..., "x": ..., "y": ...}. x and y can be null for a device not yet placed. Can be empty
deviceValuesList of {"field": ..., "thresholds": [...], "isStarred": ...}, the values shown for each device. Can be empty
deviceMarkerTypecircle, ring, dot, square or seat
shouldSnapToGridBoolean
gridCellSizeWhole 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.

OptionalValues
viewIdId of a saved map view. Map views are stored by the control panel, not the REST API, so pick one there
imageIdImage _id of an overlay image
createGeofenceEnabledBoolean
{"width": 16, "height": 14, "template": "map", "settings": {}}

commandButtons​

Buttons that trigger a rule. User guide: Command buttons.

RequiredValues
buttonsAt least one button, each with ruleV2Id, triggerNodeId and label
  • ruleV2Id is the rule's _id from GET /api/rules-v2.
  • triggerNodeId is the id of a node in that rule's definition.nodes with type: "trigger" and config.resourceType: "button". Only rules with such a node can be used.
  • Each button can also have icon, color (default blue), iconOnly and textAlign.

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"}
]
}
}

A button that opens another dashboard. User guide: Navigation.

RequiredValues
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.

RequiredValues
resourcedevices, 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.

OptionalValues
resourceTypedevice (default), connector, userGroup, organization or ruleV2
typeList of error, warning, info, verbose, debug
priorityList of severe, high, medium, low
categoryupdate, command, status, access, analytics, rule or system
timeRangeFor example {"start": {"type": "relative", "amount": 24, "unit": "hours"}, "end": {"type": "now"}}
titleString
{
"width": 14, "height": 14,
"template": "logs",
"settings": {"type": ["error", "warning"], "priority": ["severe", "high"]}
}

text​

Free text. User guide: Text.

RequiredValues
textNot empty
alignmentleft, center or right
colorColour
fontSizexs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl or 6xl
decorationnone, 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.

RequiredValues
imageIdImage _id
imageSizesmall, medium or large
shapenone, rounded or full
backgroundno-background or background
horizontalAlignmentleft, center or right
verticalAlignmentupp, 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​