Advanced Features

The API provides a standard set of features that are available on most endpoints.

Pagination

The API provides pagination functionality via the parameters page, per-page. Endpoints that support pagination will have the ?page and ?per-page GET parameters in the documented options.

Example:

  • To get 20 records per page, User would make request with query parameter: ?per-page=20. In the response User should get records 1 - 20.

  • To get second page, User would make request with query parameter: ?page=2. In the response User should get second page with records. Default per-page value will be applied to the request. Different endpoints have different default per-page values.

  • You can also combine this query parameters, for example to get per page 20, and second page. User would make request with following query parameters: ?per-page=20&page=2. In the response User should get records from 21 - 40.

Example _meta object

"_meta": {
    "totalCount": 246,
    "pageCount": 13,
    "currentPage": 1,
    "perPage": 20
}

Field

Description

totalCount

Total count of records in collection - User have access to

pageCount

Total page count of records in collection - User have access to, with respect to perPage value. If not set as query parameter. Default one will be applied and returned in response

currentPage

Currently requested page

perPage

Count of records returned on one page

The same information is available in the response headers.

Example pagination headers

x-pagination-current-page: 1 
x-pagination-page-count: 13 
x-pagination-per-page: 20 
x-pagination-total-count: 246

Field
Description

x-pagination-total-count

Total count of records in collection - User have access to

x-pagination-page-count

Total page count of records in collection - User have access to, with respect to perPage value. If not set as query parameter. Default one will be applied and returned in response

x-pagination-current-page

Currently requested page

x-pagination-per-page

Count of records returned on one page

HEAD request

Sometimes User is not interested in getting records itself, but wants to get the number of records. It is possible by making a HEAD request to the same collection API endpoint.

For example we would like to get all groups in the system User have access to.

HEAD https://dashboard.bace-iot.com/api/v2/group

It will not return anything in the body of response. But in the Headers you will be able to find pagination Headers

Expand

It is often useful to expand the response with extra optional attributes or nested relations. If you want to know what are optional expand options for your request, you can find expand option array, if you make GET request to collection endpoint.

GET https://dashboard.bace-iot.com/api/v2/physical-device

{
    "items": [
        ...
    ],
    "expand": [
        "latestEvent",
        "group",
        "parent",
        "deviceType",
        "location",
        "iotDevice",
        "deviceInfo",
        "modbusTemplateHistory",
        "currentModbusTemplate",
        "simCard"
    ]
}

Expand options array is available only in collection endpoint, but can be used in the same way on collection and singleton endpoints

By passing one or more (comma seperated) to the "expand" parameter, you can drill down into further relations, as in example of parentGroup.physicalDevices.

For example from Physical Device endpoints , you may request a comma-separated list by using ?expand=group,parent,parent.group, which will return a response that contains Physical Device information, it’s Group information, also parent Physical Device and it’s Group information.

GET https://dashboard.bace-iot.com/api/v2/physical-device/0235e44c-…?expand=group,parent,parent.group

Example response:

{
    "id_physical_device": "0235e44c-...",
    "serial_hardware": "d88...",
    "label": "Device Label",
    "id_parent": "39ee0b23-...",
    "id_group": "4bb7b680-...",
    "id_device_type": "refrigerator",
    "id_iot_device": null,
    "is_connected": 0,
    "expected_offline_interval": null,
    "expected_live_status": null,
    "device_status": null,
    "connection": null,
    "created_at": 1617022239,
    "last_data_at": 1617962070,
    "signal": 0,
    "commissioned_at": null,
    "calibrated_at": 0,
    "reconnected_at": null,
    "bace_software_version": null,
    "app_software_version": null,
    "archived_serial": null,
    "archived_at": null,
    "archived_by": null,
    "group": {
        "id": "4bb7b680-...",
        "id_group": "4bb7b680-...",
        "label": "Refrigerator Leiden 1",
        "type": "5003",
        "type_label": "Loose Device",
        "subtype": "Refrigerator",
        "id_country": "b8415b65-...",
        "created_at": 1617351877,
        "_links": {
            "self": {
                "href": "/api/v2/group/4bb7b680-..."
            },
            "index": {
                "href": "/api/v2/group/index"
            },
            "data": {
                "href": "/api/v2/data?filter[id_group]=4bb7b680-..."
            },
            "downsampled_data": {
                "href": "/api/v2/data-downsampled?filter[id_group]=4bb7b680-..."
            },
            "raw_data": {
                "href": "/api/v2/data/index?filter[id_group]=4bb7b680-..."
            }
        }
    },
    "parent": {
        "id_physical_device": "39ee0b23-...",
        "serial_hardware": "b8f009804ef4",
        "label": "BACE-18",
        "id_parent": null,
        "id_group": "0e5144e0-...",
        "id_device_type": "refrigerator",
        "id_iot_device": "9d80b382-dce5-4fd5-a9ed-ec9fb24d37e2",
        "is_connected": 0,
        "expected_offline_interval": null,
        "expected_live_status": null,
        "device_status": null,
        "connection": "cellular",
        "created_at": 1617021509,
        "last_data_at": 1619128818,
        "signal": 0,
        "commissioned_at": null,
        "calibrated_at": null,
        "reconnected_at": null,
        "bace_software_version": null,
        "app_software_version": null,
        "archived_serial": null,
        "archived_at": null,
        "archived_by": null,
        "group": {
            "id": "0e5144e0-...",
            "id_group": "0e5144e0-...",
            "label": "Test-Building-1",
            "type": "50000",
            "type_label": "Building",
            "subtype": "bace-ep",
            "id_country": "b8415b65-...",
            "created_at": 1617021758,
            "_links": {
                "self": {
                    "href": "/api/v2/group/0e5144e0-..."
                },
                "index": {
                    "href": "/api/v2/group/index"
                },
                "data": {
                    "href": "/api/v2/data?filter[id_group]=0e5144e0-..."
                },
                "downsampled_data": {
                    "href": "/api/v2/data-downsampled?filter[id_group]=0e5144e0-..."
                },
                "raw_data": {
                    "href": "/api/v2/data/index?filter[id_group]=0e5144e0-..."
                }
            }
        },
        "_links": {
            "self": {
                "href": "https://dashboard.bace-iot.com/api/v2/physical-device/view?id=39ee0b23-..."
            },
            "index": {
                "href": "https://dashboard.bace-iot.com/api/v2/physical-device/index"
            }
        }
    },
    "_links": {
        "self": {
            "href": "https://dashboard.bace-iot.com/api/v2/physical-device/view?id=0235e44c-..."
        },
        "index": {
            "href": "https://dashboard.bace-iot.com/api/v2/physical-device/index"
        }
    }
}

In the device object, User will find group object, it is Group record related to Physical Device. Also User will find parent object, it is parent Physical Device, and inside User will found another group object - it is Group of parent Physical Device.

Fields

We recommend that you always filter only on the fields that you need for your request. This speeds up the response time and reduces the amount of data being transferred between servers. A comma-separated list of fields can be provided to achieve this. For example we will extend previous request and will request only labels, ?expand=group,parent,parent.group&fields=label,group.label,parent.label,parent.group.label will return a response that contains only the label for every record.

GET https://dashboard.bace-iot.com/api/v2/physical-device/0235e44c-…?expand=group,parent,parent.group&fields=label,group.label,parent.label,parent.group.label

Response:

{
  "label": "Device Label",
  "group": {
      "label": "Refrigerator Leiden 1",
      "_links": []
  },
  "parent": {
      "label": "BACE-18",
      "group": {
          "label": "Test-Building-1",
          "_links": []
      },
      "_links": {
          "self": {
              "href": "dashboard.bace-iot.com/api/v2/physical-device/view?id=39ee0b23-..."
          },
          "index": {
              "href": "dashboard.bace-iot.com/api/v2/physical-device/index"
          }
      }
  },
  "_links": {
      "self": {
          "href": "https://dashboard.bace-iot.com/api/v2/physical-device/view?id=0235e44c-..."
      },
      "index": {
          "href": "https://dashboard.bace-iot.com/api/v2/physical-device/index"
      }
  }
}

You can find that 120 lines in response reduced to 30 lines. It allows queries to run faster, especially if you increasing default per-page for requests on collection endpoints. But we in general recommend to limit fields for every request and get just required fields.

Sort

Some attributes can be sorted using the ?sort query parameter. For example, making a GET request on an index with ?sort=label will do an ascending sort on the label attribute. Sorting on strings will do a natural sort, whereas sorting on a numeric value will do a numeric sort instead. Its also possible to invert a sort by prefixing the attribute name with a minus sign. ?sort=-timestamp results in sorting timestamps from newest to oldest.

Filter

Filtering on most attributes is available via the filter query parameter. For example, to filter on the label attribute, you can use ?filter[label]=MyLabel to filter on an exact match, or ?filter[label][like]=Label to do a like-match. Available operators (depending on datatype) are

Operator
Example
Explanation

=

filter[label]=MyLabel

for an explicit exact match

for an explicit exact match

filter[label][eq]=A1

for an explicit exact match

neq

filter[label][neq]=A1

for not equal to

like

filter[label][like]=Label

for a partial match that ignores capitalization

lt

filter[timestamp_seconds][lt]=1648038180

to filter only on attributes lower than the provided value

lte

filter[timestamp_seconds][lte]=1648038180

to filter only on attributes lower-or-equal than the provided value

gt

filter[timestamp_seconds][gt]=1648038180

to filter only on attributes greater than the provided value

gte

filter[timestamp_seconds][gte]=1648038180

to filter only on attributes greater-or-equal than the provided value

in

filter[label][in][0]=A1&filter[label][in][1]=A2

to filter on array of values. [field] + [in] + [index number]

or

filter[or][0][label][like]=b2&filter[or][1][label][like]=b1

or operator (||). [or] + [index number] + [field] + [like]

and

filter[and][0][label][like]=bace&filter[and][1][label][like]=acc/gyro

and operator (&&). [and] + [index number] + [field] + [like]

In some cases it is possible to filter on relationships from the Expand option. Support for this is being expanded currently where it is useful.

Filter with JSON body

It is also possible to build your more complicated queries and send it not as a query parameters, but with a json body.

To make use of this you are required to make your request with the header: Content-Type: application/json

Request body

{
    "filter": {
        "or": [
            {
                "label": {
                    "like": "site"
                }
            },
            {
                "type": 5003
            }
        ]
    }
}

This request would be equal to ?filter[or][0][label][like]=site&filter[or][1][type]=5003, if you prefer to use your filters as a query parameters. All the operators for JSON body filters are the same as operators for filter in query parameters.

!Important: The API will only accept a URL-parameter GET or a Body, it will not merge them if both are provided; the URL parameters will take precedence.

Many pages and objects will have a "_links" attribute which represents a list of useful resources related to this response or object.

For example, our pagination will add pre-built links for the current, next, previous and last page of the result, allowing you to quickly use these in building buttons in your frontend that follow our URL scheme. Many objects will also contain a _links attribute that will point you to endpoints for relevant relational objects, datasets to query or the location of the index endpoint for that particular type of object.

Labels

In some of API calls, you will find labels, which can be used to better understand meaning of fields in the response object. For example endpoint to remove z-wave node:

DELETE https://dashboard.bace-iot.com/api/v2/physical-device/04771e4c-…/zwave-node

Example response

{
  "message": "We are processing your request. You can use API event endpoint to get information about your request status.",
  "routeToPollEvents": "https://dashboard.bace-iot.com/api/v2/event?filter[source_device]=04771e4c-...&filter[event_type]=612&sort=-created_at",
  "tips": [
    {
      "id": 0,
      "label": "Success"
    },
    {
      "id": 7,
      "label": "Exclusion failed"
    },
    {
      "id": 255,
      "label": "Failed"
    }
  ],
  "fromCloud": {
    "status": 200,
    "payload": {
      "result": "success"
    }
  }
}

Fields
Description

fromCloud

Is response User got from IoT Hub

message

Message generated by BACE Cloud

routeToPollEvents

This is endpoint, User can use to listen to get result of asynchronous action

tips

Array of possible event values, you can receive from routeToPollEvents. So if you get event with value 0 - it would mean a success in z-wave node exclusion.

Last updated