# Welcome!

## Welcome to BACE

BACE is a multipurpose device-to-cloud solution, enabling the user to measure and receive data in an easy, fast, and secure way.

Here you'll find all documentation you need to get up and integrate BACE data directly to your application. The BACE API implements REST architecture. REST is an architectural style that uses HTTP to get data through a common interface. We adhere to a unified naming convention for most endpoints, which are available through our Swagger documentation.

The BACE API allows you to

* Configure and organize your project
* Manage system users / devices / locations / access
* Get measurements data & events from devices
* and more

## Want to jump right in?

Feeling like an eager beaver? Jump in to the quick start docs and get making your first request:

{% content-ref url="/pages/7asvnA30sI5Jt3Jn59nI" %}
[Quick Start](/quick-start)
{% endcontent-ref %}

## Want to deep dive?

Dive a little deeper and start exploring BACE System to get an idea of everything that's possible with the API:

{% content-ref url="/pages/mercwfmh2slmxNMVQfqp" %}
[System Overview](/system-overview)
{% endcontent-ref %}


# Quick Start

## Get your API tokens

Your API requests are authenticated using API tokens. Any request that doesn't include an API token will return [return error 401](/reference/http-status-codes#unauthorized-401).

You can request your API tokens from your Evalan representative at any time. Don't know how to authenticate? Read how in the *Authentication* section.

{% content-ref url="/pages/gYMy8eifc455FqfXTwzG" %}
[Authentication](/api/authentication)
{% endcontent-ref %}

## Make your first request

To make your first request, send an authenticated request to the `physical-device` endpoint. This will list all physical devices assigned to your account.

{% openapi src="/files/fukFlIeGTGGfmSpBVkRQ" path="/api/v2/physical-device" method="get" %}
[BACE API.json](https://2186022299-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQAP1rE2NAOVH04TQmlau%2Fuploads%2F9pQVmWjuBJkB5cXuJvCS%2FBACE%20API.json?alt=media\&token=7ac4957e-ae9f-4dc1-b332-262fc080096e)
{% endopenapi %}

```
curl https://dashboard.bace-iot.com/api/v2/physical-device
    -H "Content-Type: application/json"
    -H "Authorization: Bearer ab183f15bd437fbdb8a1235be0f3b784729d737d"
```


# System Overview

## Introduction

BACE is a multipurpose device-to-cloud solution, enabling the user to measure and receive data in an easy, fast, and secure way. Users can connect their devices to an enterprise system using BACE with a few lines of code.

The BACE system consists out of two main components: the IoT Connectivity Module and the IoT Connector. BACE integrates seamlessly with your assets and enterprise system. A schematic overview of the system is shown below with a more detailed description of each part of the system.

![BACE System Overview](/files/IsAK52lqDpQCVkOB6clj)

### Your Device

This could be any device that you would like to get connected in order to unlock the power of IoT. You can think of a sensor, a machine, an appliance, a wearable or any other type of hardware device.&#x20;

### IoT Connectivity Module

There are three different IoT Connectivity Modules: BACE Core, BACE Plus and BACE Go. Each module comes in a different form factor and supports a wide range of communication protocols to speak with your device. The information fetched from your asset by IoT Connectivity Module is sent to cloud via cellular, WiFi or Ethernet communication. [More information about different modules could be found here.](https://www.bace-iot.com/products/hardware-module)

### IoT Connector

IoT Connector is a group of cloud applications to manage bi-directional device communication and store your device data. The asset information is exposed as an API service or webhook so that it can be connected to enterprise systems with a few lines of code. The API endpoints could be used for fetching the latest data from your device, retrieve historical device data from IoT Connector, and get any event errors occurred between your asset and IoT Connectivity module. Each API call is checked against the user accounts rights before replying information.

[Webhooks ](broken://pages/UVSsgFpetKsHX9T7LZ9r)are usually setup to get notifications immediately when new data is fetched from your device. The big difference compared to API is that the latest data is automatically published to your endpoint and where as you need to poll API endpoints in regular basis to check if there is an update.

In order to do your first API call you will need to sign in with a valid user account. Read how to authenticate in the next section.


# BACE Panel

*BACE Panel* enhances the flexibility of [BACE IoT](https://evalan.com/bace-iot-gateways/) as a comprehensive solution and optimizes the user experience throughout the entire device management process, from onboarding to configuring and monitoring.

Here are a few things you can do with BACE Panel:

1. Onboard new BACE Gateways and customer assets such as Modbus devices
2. Visualize the status of the entire data pipeline in real time.
3. Change configurations of BACE Gateways and Modbus devices.

Here you will find some walkthroughs on how to onboard different types of devices.


# How To Onboard Modbus Devices

Here is a step-by-step guide for onboarding Modbus Devices

:tv: Do you prefer watching instead of reading the walkthrough, then check the video below.

{% embed url="<https://youtu.be/1OYqfeX5iQ8>" %}

## **Step-by-Step Walkthrough**

**1.** Go to the portal ([panel.bace-iot.com](https://panel.bace-iot.com/)) and log in with your username and password:

<figure><img src="/files/7QQnwmSnbfYv804Bd4RX" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/AX2Zu5uNUWFxPCmd51oa" alt=""><figcaption></figcaption></figure>

Press **continue** when prompted to access BACE Cloud:

<figure><img src="/files/100It2QyIQuzjJThYH9Q" alt=""><figcaption></figcaption></figure>

**2.** Once you are on the home screen, click on the “**Modbus Devices**” button to add a new device to your dashboard:

<figure><img src="/files/SaBPAJD4ZGKYBBUnTFYa" alt=""><figcaption></figcaption></figure>

**3.** Click the “**Add new gateway**” button:

<figure><img src="/files/tHMuPDY0sOhqx1DkVZ04" alt=""><figcaption></figcaption></figure>

**4.** Read the overall steps and click **“Let's Start”** to proceed:

<figure><img src="/files/KY9Gehx76naRAlVqzD9v" alt=""><figcaption></figcaption></figure>

**5.** Select the gateway you want to connect your Modbus device to. Corresponding **IoT ID** is on the sticker located on BACE gateway housing. Then press on the “Next > Set Gateway” button:

<figure><img src="/files/qOfPqe9yptzjkGpBrE4S" alt=""><figcaption></figcaption></figure>

**6.** Set a name for the template label:

<figure><img src="/files/LeP54C4lR1scGZEM655Z" alt=""><figcaption></figcaption></figure>

Select the Modbus Mode. Choose between **Modbus RTU** and **Modbus TCP**. You can find this information in the manual of your Modbus Device:

<figure><img src="/files/NgTOaYVS40xGiZjad67p" alt=""><figcaption></figcaption></figure>

Select the **Baud Rate**. You can find this information in the manual of your Modbus Device:

<figure><img src="/files/MqHuV3B4FczvtCSWUNlH" alt=""><figcaption></figcaption></figure>

Select the interval. The interval is the time frequency in which every register will be read by BACE gateway and sent to BACE IoT Platform. Press the “Next > Set Modbus Devices” button to proceed:

<figure><img src="/files/XOpTbHWi405lYAc6xoAM" alt=""><figcaption></figcaption></figure>

**7.** Set a Slave ID for your Modbus Device.

<figure><img src="/files/ashs6E32UrLbINEFrYhG" alt=""><figcaption></figcaption></figure>

Set the Byte order and the Word order. For both, choose between Little Endian and Big Endian. You can find this information in the manual of your Modbus Device:

{% hint style="info" %}
If you don't know the [endianness](https://en.wikipedia.org/wiki/Endianness) of the device, leave it at default. You can change this setting later if you are getting ambiguous readings
{% endhint %}

<figure><img src="/files/rvFa4SUekVQh6T7i0Vys" alt=""><figcaption></figcaption></figure>

You can add another Modbus device by clicking **(+)** below Slave ID. When you are finished with adding devices, click the “Next > Add Registers” button:

<figure><img src="/files/Eq43I2cwrruOShvfBjKW" alt=""><figcaption></figcaption></figure>

**8.** Here you can define registers for your Modbus Device.

First, set the Label and the Unit to be shown on your dashboard. You can find the appropriate values to set the Register Start and Scale magnitudes in the manual of your Modbus Device.

<figure><img src="/files/Scr2Lj66DBTyrxoE2kB9" alt=""><figcaption></figcaption></figure>

Then, set **Register Type** (Holding or Input), **Data Type** and **Access Mode**. Fill this information per instruction per your Modbus Device manual:

<figure><img src="/files/OrZddeLS9ncOhn27oeh4" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/SPeXMyA5M3YbIPBLKWCc" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/nTOr9omgyiHIg7bqBWdv" alt=""><figcaption></figcaption></figure>

You can also add a new register, and/or duplicate one of the registers that you already have. When you are finished with the registers, press “Apply”:

<figure><img src="/files/JW4j7rfTUALwFrFXaVMl" alt=""><figcaption></figcaption></figure>

**9.** You can instantly review the information you just set. If anything needs to be changed, you can press the “Edit” button. You can return to the Modbus Devices overview by clicking on the “Go to Modbus Devices” button. If you click the “**click here**” link (as shown in the picture), you will go to the overview of the Modbus Device you just connected:

<figure><img src="/files/U4e7Aw05njDoPCb1Sn3p" alt=""><figcaption></figcaption></figure>

**10.** You can now see that your Modbus Device is linked. Click on the Modbus Devices area to see the details:<br>

<figure><img src="/files/7dfn3oQFFTBoRYZsoWVe" alt=""><figcaption></figcaption></figure>

11. Congrats! You have just connected a Modbus Device to BACE gateway and you should be able to see information from the Modbus device! If you want to make some changes click **Configure,** or you can connect a new Modbus Device to another gateway by clicking **Add New Gateway**:

<figure><img src="/files/z5qTvC6N3icfflgiQAC3" alt=""><figcaption></figcaption></figure>


# Creating Webhooks

## Step by Step Walkthrough

1. Login to your account in [panel.bace-iot.com](https://panel.bace-iot.com/).
2. Click into Project you want to setup a webhook.

<figure><img src="/files/otyHGVtcoxJS4L1326HL" alt=""><figcaption></figcaption></figure>

3. From left navigation, go to Integration -> Webhooks

<figure><img src="/files/J1r4kPzv7tFD4gA4TusF" alt=""><figcaption></figcaption></figure>

4. Click Create Webhook button and fill in the details accordingly:

**Webhook Label:** Provide a name that will help you remember what the webhook is for

**Forwarding Type:** Select Measurements or Events, this determines the type of information you are sending in the webhook&#x20;

* Measurements is for sending values of the data types (i.e. Temperature: 27.8 C) [BACE Webhooks](/integrations/bace-webhooks#sending-measurements-as-a-webhook)
* Events is for sending platform specific events (i.e. Device Online) [BACE Webhooks](/integrations/bace-webhooks#sending-events-as-a-webhook)

**Webhook formatter:** Select one of the available formatter. More details on formatters and example response can be found on [BACE Webhooks](/integrations/bace-webhooks#how-to-use-bace-webhooks)

**Authorization:** Add your authorization token. Some examples are `Bearer <TOKEN>` or `ApiKey <TOKEN>`

<figure><img src="/files/iq1YOi29JK7owWM8ieO5" alt=""><figcaption></figcaption></figure>

5. Click create and you are done! You can check the response codes of the webhooks by clicking into Webhook Attempts tab.

<figure><img src="/files/3rjPkgqIaUKJxbEu0KiF" alt=""><figcaption></figcaption></figure>


# Get Started Using Postman

Here are instructions to get you onboarded using Postman

Although we covered each endpoint in the following chapters, if you are familiar with using [Postman](https://www.postman.com/downloads/), here are some files with example commands to get started very quick!

1. Download the following BACE Postman collection and environment files to your laptop:

{% file src="/files/uDv4B8hQZLWVLlMm9eVK" %}
Postman Collection File
{% endfile %}

{% file src="/files/G8MxSxW4XqdTXO2KapjJ" %}
Postman Environment File
{% endfile %}

2. Import both collection and environment files into your Postman.

<figure><img src="/files/KgdLOlM4DL95C2Y9aiVK" alt=""><figcaption><p>Import Collection</p></figcaption></figure>

<figure><img src="/files/DXbCqb489aR9rD8iLVK5" alt=""><figcaption><p>Import Environment</p></figcaption></figure>

3. Fill in your API credentials in BACE PROD environment. Before leaving this page make sure it is **saved** and you have switched to **BACE PROD** environment.

<figure><img src="/files/8GPxmfhZrgTz3BbflybB" alt=""><figcaption><p>BACE Environment Settings</p></figcaption></figure>

{% hint style="info" %}
Please reach out your Evalan representative to get **client\_id** and **client\_secret** if you don't have them yet.
{% endhint %}

4. Go ahead try if Request Oauth2 Token (Password Grant) request in Authentication & Self to see if you are set up properly. You could receive a token and that will be automatically used for any requests in this collection file&#x20;

<figure><img src="/files/JlgcCeC8Gtb2JOSbv1Jd" alt=""><figcaption><p>Successful token result</p></figcaption></figure>

5. Next you can try calling an example API such as physical devices to see all gateways assigned to your account.

<figure><img src="/files/lRZXYiUVHUANGkwVae1E" alt=""><figcaption></figcaption></figure>

That's it, you are on BACE IoT Platform now! Feel free to check the next chapters to discover how BACE APIs work and understand the responses.


# Authentication

## Introduction

The BACE API uses oAuth2 for authorizing API requests. Each request to the BACE API must be signed with valid Bearer access token in the Authorization header. If the Authorization header is missing or invalid, the API will give you a warning.

Requesting and using the token follows the following flow:

1. **Request** access token for *first time* access.
2. **Set** access token in the Authorization header with "Bearer" prefix.
3. **Refresh** access token when expired.

&#x20; How to request and refresh your API token is explained below.&#x20;

{% hint style="info" %}
Some endpoints require more permissions than the account has access to. If your account lacks the permission to access an endpoint, we will return a HTTP 401 "Unauthorized" response. We show all endpoints that you may have access to in the documentation and it is up to your implementation to handle this response gracefully
{% endhint %}

## First time access: request API token

When you first connect to the API you will need to request a new Bearer Token. For this you will require a BACE account, with client secret and client ID. Contact your Evalan representative if you haven't received these credentials.

In case you have your secure backend server, you can get an API token by making POST request to our authorization endpoint. Requesting a token requires a POST as form-data:

## Request token

<mark style="color:green;">`POST`</mark> `https://dashboard.bace-iot.com/oauth2/token`

Post as form-data

#### Request Body

| Name                                             | Type   | Description                                                           |
| ------------------------------------------------ | ------ | --------------------------------------------------------------------- |
| client\_id<mark style="color:red;">\*</mark>     | String | client\_id should be request from bace-iot.com                        |
| client\_secret<mark style="color:red;">\*</mark> | String | client\_secret should be requested from bace-iot.com                  |
| grant\_type<mark style="color:red;">\*</mark>    | String | grant\_type is always "password"                                      |
| username<mark style="color:red;">\*</mark>       | String | The username of your BACE account. Normally this is an email address. |
| password<mark style="color:red;">\*</mark>       |        | The user password of your BACE account.                               |

{% tabs %}
{% tab title="200: OK Authorization succeeded" %}

```javascript
{
    "access_token": "8a0b...", - BACE API Authorization token
    "expires_in": 86400, - token expiration (seconds)
    "token_type": "Bearer", - token type
    "scope": null, - scope is not used for now in the system
    "refresh_token": "1281..." - token, which can be used to refresh BACE API token
}
```

{% endtab %}

{% tab title="400: Bad Request Request was made with wrong params" %}

```javascript
{
    "name": "Bad Request",
    "message": "This client is invalid or must authenticate using a client secret",
    "code": 0,
    "status": 400,
    "type": "filsh\\yii2\\oauth2server\\exceptions\\HttpException"
}
```

{% endtab %}

{% tab title="401: Unauthorized Request was made with invalid credentials." %}

```javascript
{
    "name": "Unauthorized",
    "message": "Invalid username and password combination",
    "code": 0,
    "status": 401,
    "type": "filsh\\yii2\\oauth2server\\exceptions\\HttpException"
}
```

{% endtab %}
{% endtabs %}

In this example, username and passwords are the same credentials you would use to login to the Dashboard; so you would use an email address as the username. The grant\_type must always be “password” and the client\_id and client\_secret are specific to the software client that has been registered.

Now you can set your Authorization header with your newly retrieved BACE Access Token. Use this header for every API request you will do from this point onwards. For example:

```
curl https://dashboard.bace-iot.com/api/v2/physical-device
    -H "Content-Type: application/json"
    -H "Authorization: Bearer 8aob..."
```

{% hint style="info" %}
Avoid creating new tokens when the old token can still be used securely. Instead use the Refresh Token endpoint introduced below.&#x20;
{% endhint %}

## Refresh access token

For security reasons, your token will not be valid indefinitely and needs refreshing. A newly issued token is valid for 24h. Refreshed tokens are valid for 14 days.

This endpoint should be called to refresh your valid token when it nears expiration. Refreshing can be done by making a request with the following POST as form-data:

## Refresh token

<mark style="color:green;">`POST`</mark> `https://dashboard.bace-iot.com/oauth2/token`

Post as form-data

#### Headers

| Name                                            | Type   | Description                                       |
| ----------------------------------------------- | ------ | ------------------------------------------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer followed by a space and your access token. |
| Content-Type                                    | String | For example: application/json                     |

#### Request Body

| Name                                             | Type   | Description                                             |
| ------------------------------------------------ | ------ | ------------------------------------------------------- |
| refresh\_token<mark style="color:red;">\*</mark> | String | Refresh token you received with upon your first request |
| client\_secret<mark style="color:red;">\*</mark> | String | client\_secret should be requested from bace-iot.com    |
| client\_id<mark style="color:red;">\*</mark>     | String | client\_id should be requested from bace-iot.com        |
| grant\_type<mark style="color:red;">\*</mark>    | String | refresh\_token                                          |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "refreshed": true,
    "expires": "2022-04-04 14:19:49" - new expiration should be 14 days from now 
}
```

{% endtab %}

{% tab title="400: Bad Request Request was made with wrong params" %}

```javascript
{
    "name": "Bad Request",
    "message": "The grant type was not specified in the request",
    "code": 0,
    "status": 400,
    "type": "filsh\\yii2\\oauth2server\\exceptions\\HttpException"
}
```

{% endtab %}
{% endtabs %}

Remember to set your Authorization header properly with a valid BACE API token.

{% hint style="warning" %}
Avoid creating new tokens where possible; refresh your token instead!
{% endhint %}


# Navigating Data

Before you can access your data, you first have to know what data you are interested in. In the BACE system your data is structured in such a way that it offers maximum flexibility without loosing access simplicity. There are three main components to this structure:

1. **Groups**
2. **Physical Devices**
3. **Data Sessions**\
   *Data sessions are only applicable for users of BACE Go and are explained in* [*a separate section*](/api/data-sessions)*. Not sure what device you have? Take a look* [*here*](/reference/powering-iot-connectivity-modules)*!*&#x20;

### Navigating Groups

Every BACE Connectivity Module is linked to a group. Groups are data containers; when the BACE Connectivity Module receives data, it is relayed and stored in the respective group. Groups therefore provide access to the data of your Connectivity Module and any device that is connected to it.

Groups can be identified by their unique *id\_group*. A list of groups that you have access to can be retrieved using the `group` endpoint:

## Index groups

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/group/index`

Respond will consist of a list of your data groups

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "items": [
        {
            "id": "0fcf513b-...",
            "id_group": "0fcf513b-...",
            "label": "Demo Group",
            "type": "5003",
            "type_label": "Loose Device",
            "subtype": "activity-monitors",
            "id_country": "b8415b65-...",
            "created_at": 1633093198,
            "deleted_at": null,
            "_links": {
                "self": {
                    "href": "/api/v2/group/0fcf513b-..."
                },
                "index": {
                    "href": "/api/v2/group/index"
                },
                "data": {
                    "href": "/api/v2/data?filter[id_group]=0fcf513b-..."
                },
                "downsampled_data": {
                    "href": "/api/v2/data-downsampled?filter[id_group]=0fcf513b-..."
                },
                "raw_data": {
                    "href": "/api/v2/data/index?filter[id_group]=0fcf513b-..."
                }
            }
        },
}
```

{% endtab %}
{% endtabs %}

In this example the user has access to one group. The API response already provides hints on how to retrieve data from the device(s) in this group. This is explained further in the next section.

{% content-ref url="/pages/2WidhXHFySLtdGx5isBW" %}
[Accessing Data](/api/accessing-data)
{% endcontent-ref %}

### Navigating Physical Devices

Physical devices are any devices in your IoT project. This includes your BACE Connectivity Module, sensors, devices, and other assets that are connected to BACE products.

All physical devices are identified by the unique `id_physical_device` parameter. Like the `group` endpoint, a list of accessible physical devices can be retrieved.

{% openapi src="/files/T1yretTJg4kfgumUz16J" path="/api/v2/physical-device" method="get" %}
[json.json](https://2186022299-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQAP1rE2NAOVH04TQmlau%2Fuploads%2FfLooxILGEvc8m57FzABc%2Fjson.json?alt=media\&token=cc3645eb-d663-4ed7-b6b6-0e9ae23f8633)
{% endopenapi %}

Let's evaluate how the response looks like for this command. Please note that for ease of reading some filters are applied and the response is truncated so it will look different than what you get.

<mark style="color:blue;">`GET`</mark>`https://dashboard.bace-iot.com/api/v2/physical-device?fields=id_physical_device,label,last_data_at`

```json
{
    "items": [
        {
            "id_physical_device": "000795be-a92d-4f05-a21a-2d1b7759609a",
            "label": "BACE100",
            "last_data_at": 1655804141,
        },
        {
            "id_physical_device": "00117ccb-5577-4de4-8613-7af314327fe3",
            "label": "BACE101",
            "last_data_at": 1635377064,
        },
        {
            "id_physical_device": "002ab67b-867b-458d-9e11-87f053e003ea",
            "label": "BACE102",
            "last_data_at": 1630579789,
        }
    ]
}
```

The response above lists three Connectivity Modules assigned to your account and displays unique physical device ID, label and last time Module sent data to Cloud information. In practice it is important to keep a list of all physical device ids in your own database so that you know which device you are working on when you read/write attributes.

Both endpoints in this section can also be used with [Advanced Features](/api/advanced-features). In the example below we use expand on group to get an overview of all groups that each physical device is linked to:&#x20;

## Access physical device data

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device?expand=group`

Response will be a paginated list of datapoints that are available in the group.

#### Query Parameters

| Name   | Type  | Description |
| ------ | ----- | ----------- |
| expand | group |             |

{% tabs %}
{% tab title="200: OK " %}

```json
{
 {
    "items": [
        {
            "id_physical_device": "007ed6e0-...",
            "serial_hardware": "b8f00...",
            "label": "",
            "id_parent": null,
            "id_group": "b7624b4d-...",
            "id_device_type": "bace-plus-app",
            "id_iot_device": "366ff2e7-...",
            "is_connected": 1,
            "expected_offline_interval": 0,
            "expected_live_status": 0,
            "device_status": 0,
            "connection": "cellular",
            "created_at": 1647955678,
            "last_data_at": 1648044742,
            "signal": 75,
            "commissioned_at": null,
            "calibrated_at": null,
            "reconnected_at": null,
            "bace_software_version": "1.13.0",
            "app_software_version": "1.2.13",
            "archived_serial": null,
            "archived_at": null,
            "archived_by": null,
            "group": {
                "id": "b7624b4d-...",
                "id_group": "b7624b4d-...",
                "label": "BacePlus-001-...",
                "type": "...",
                "type_label": "Loose Device",
                "subtype": "subtype",
                "id_country": null,
                "created_at": 1647963043,
                "_links": {
                    "self": {
                        "href": "/api/v2/group/b7624b4d-..."
                    },
                    "index": {
                        "href": "/api/v2/group/index"
                    },
                    "data": {
                        "href": "/api/v2/data?filter[id_group]=b7624b4d-..."
                    },
                    "downsampled_data": {
                        "href": "/api/v2/data-downsampled?filter[id_group]=b7624b4d-..."
                    },
                    "raw_data": {
                        "href": "/api/v2/data/index?filter[id_group]=b7624b4d-..."
                    }
                }
            },
            "_links": {
                "self": {
                    "href": "https://dashboard.bace-iot.com/api/v2/physical-device/view?id=007ed6e0-..."
                },
                "index": {
                    "href": "https://dashboard.bace-iot.com/api/v2/physical-device/index"
                }
            }
        }
    ],
    "_links": {
        "self": {
            "href": "https://dashboard.bace-iot.com/api/v2/physical-device?expand=group&page=1"
        },
        "first": {
            "href": "https://dashboard.bace-iot.com/api/v2/physical-device?expand=group&page=1"
        },
        "last": {
            "href": "https://dashboard.bace-iot.com/api/v2/physical-device?expand=group&page=1"
        },
        "next": {
            "href": "https://dashboard.bace-iot.com/api/v2/physical-device?expand=group&page=2"
        }
    },
    "_meta": {
        "totalCount": 1,
        "pageCount": 1,
        "currentPage": 1,
        "perPage": 20
    },
    "expand": [
        "latestEvent",
        "group",
        "parent",
        "deviceType",
        "location",
        "iotDevice",
        "deviceInfo",
        "modbusTemplateHistory",
        "currentModbusTemplate",
        "simCard"
    ],
    "labels": {
        "id_physical_device": "Database ID",
        "label": "Label",
        "labelLink": "Label",
        "serial_hardware": "Serial",
        "group.label": "Group",
        "id_group": "Group",
        "id_device_type": "Device Type",
        "parentDevice.displayLabel": "Parent Device"
    },
    "deviceStatuses": {
        "expectedStatuses": [
            "ALWAYS_OFF",
            "ALWAYS_ON"
        ],
        "availableStatuses": [
            "EXPECTED_OFF",
            "EXPECTED_ON_DEVICE_ON",
            "EXPECTED_ON_DEVICE_OFF"
        ]
    }
```

{% endtab %}
{% endtabs %}

The API example responses already provide hints on how to retrieve data from these devices or groups. This is explained in more detail in the next section.


# Accessing Data

There are three ways of accessing your data in the BACE system:

1. **The Fastest**: the `data-downsampled` endpoint \
   Use this endpoint when you want to poll data with fast response times, e.g. for graphing purposes.
2. **The Easiest**: webhooks\
   Use a webhook when you want retrieve all raw data continuously.&#x20;
3. **The Most Precise**: the `data` endpoint\
   Use this endpoint for a one-time export of raw data over a certain time period.

The `data-downsampled` and `data` endpoints are explained in this section. Note that a separate section is dedicated to webhooks.

{% content-ref url="/pages/mPk9wx24dEtj3AtDMmf3" %}
[BACE Webhooks](/integrations/bace-webhooks)
{% endcontent-ref %}

## Accessing data, the fast way

Down-sampled data is a great way of improving performance of retrieving data. Raw data in the BACE system is aggregated per minute, hour and day for this reason. In general we recommend the `data-downsampled`endpoint for accessing data. This endpoint is the most high performing endpoint for data polling. It is excellent for graphing and visualisation purposes.

A list of all downsampled endpoints accessible by user can be retrieved as follows:

## List downsampled data

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/data-downsampled/index`

The response will be a paginated list of all downsampled endpoints accessible by the users.

{% tabs %}
{% tab title="200: OK A paginated list of all downsampled datapoints" %}

```javascript
"items": [
        {
            "id_container_data_latest": "112e51e6-...",
            "id_group": "b7624b4d-...",
            "datatype": 2073,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647907200,
            "min_val": 0,
            "max_val": 0,
            "avg_val": 0,
            "count_val": 263
        },
        {
            "id_container_data_latest": "1aec07ea-...",
            "id_group": "b7624b4d-...",
            "datatype": 2070,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647907200,
            "min_val": 0,
            "max_val": 59.5999984741,
            "avg_val": 7.93155873229467,
            "count_val": 263
        },
        {
            "id_container_data_latest": "2f333ae8-...",
            "id_group": "b7624b4d-...",
            "datatype": 2101,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647993600,
            "min_val": 43806,
            "max_val": 57005,
            "avg_val": 52856.7428571429,
            "count_val": 35
        },
        {
            "id_container_data_latest": "490beb6b-...",
            "id_group": "b7624b4d-...",
            "datatype": 5003,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647993600,
            "min_val": 0,
            "max_val": 27,
            "avg_val": 6.84732824427481,
            "count_val": 262
        },
        {
            "id_container_data_latest": "858424d7-...",
            "id_group": "b7624b4d-...",
            "datatype": 2071,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647907200,
            "min_val": 59.5999984741,
            "max_val": 59.5999984741,
            "avg_val": 59.5999984741001,
            "count_val": 263
        },
        {
            "id_container_data_latest": "8faac4b0-...",
            "id_group": "b7624b4d-...",
            "datatype": 5000,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647993600,
            "min_val": 27.7362060547,
            "max_val": 30.3244018555,
            "avg_val": 29.0922662866034,
            "count_val": 262
        },
        {
            "id_container_data_latest": "acb5d7fe-...",
            "id_group": "b7624b4d-...",
            "datatype": 2072,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647907200,
            "min_val": 390,
            "max_val": 390.6000061035,
            "avg_val": 390.079848720998,
            "count_val": 263
        },
        {
            "id_container_data_latest": "b8c1c262-...",
            "id_group": "b7624b4d-...",
            "datatype": 2100,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647993600,
            "min_val": 0,
            "max_val": 57005,
            "avg_val": 52372.1140065147,
            "count_val": 307
        },
        {
            "id_container_data_latest": "c8bb58e9-...",
            "id_group": "b7624b4d-...",
            "datatype": 2102,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647993600,
            "min_val": 43806,
            "max_val": 47836,
            "avg_val": 45072.5714285714,
            "count_val": 35
        },
        {
            "id_container_data_latest": "f54d5550-...",
            "id_group": "b7624b4d-...",
            "datatype": 5001,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1647993600,
            "min_val": 24.7131347656,
            "max_val": 33.5266113281,
            "avg_val": 27.4022924991168,
            "count_val": 262
        }
    ],
    "_links": {
        "self": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data-downsampled?filter%5Bid_group%5D=b7624b4d-...&page=1"
        },
        "first": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data-downsampled?filter%5Bid_group%5D=b7624b4d-...&page=1"
        },
        "last": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data-downsampled?filter%5Bid_group%5D=b7624b4d-...&page=1"
        }
    },
    "_meta": {
        "totalCount": 10,
        "pageCount": 1,
        "currentPage": 1,
        "perPage": 500
    }
```

{% endtab %}
{% endtabs %}

By default you will receive aggregated data per day from the device. In order to get more precise data we should request a smaller chunks of time, like so:

## Access downsampled data

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/data-downsampled`

Filters are recommend to access downsampled data. In this example, a time interval and group filter is set.

#### Query Parameters

| Name                             | Type                | Description       |
| -------------------------------- | ------------------- | ----------------- |
| filter\[id\_group]               | 4c1c81ca-...        |                   |
| filter\[timestamp\_seconds]\[gt] | 1652691600          | From timestamp    |
| filter\[timestamp\_seconds]\[lt] | 1652778001          | To timestamp      |
| sort                             | -timestamp\_seconds | Sort on timestamp |

{% tabs %}
{% tab title="200: OK Aggregated data within specified timestamps, sorted by timestamp descending." %}

```javascript
{
    "items": [
        {
            "id_container_data_latest": "c1dafb46-...",
            "id_group": "4c1c81ca-...",
            "datatype": 5205,
            "source_device": "6b88b4df-...",
            "timestamp_seconds": 1652706000,
            "min_val": 4.106001,
            "max_val": 4.21,
            "avg_val": 4.12140803703704,
            "count_val": 27
        },
        {
            "id_container_data_latest": "f2d754ba-...",
            "id_group": "4c1c81ca-...",
            "datatype": 6000,
            "source_device": "8329650b-...",
            "timestamp_seconds": 1652706000,
            "min_val": 1,
            "max_val": 1,
            "avg_val": 1,
            "count_val": 27
        },
        {
            "id_container_data_latest": "8e00087e-...",
            "id_group": "4c1c81ca-...",
            "datatype": 6000,
            "source_device": "d6a18bf2-...",
            "timestamp_seconds": 1652702400,
            "min_val": 100,
            "max_val": 103,
            "avg_val": 101.5,
            "count_val": 2
        },
        {
            "id_container_data_latest": "c1dafb46-...",
            "id_group": "4c1c81ca-...",
            "datatype": 5205,
            "source_device": "6b88b4df-...",
            "timestamp_seconds": 1652702400,
            "min_val": 4.090001,
            "max_val": 4.126667,
            "avg_val": 4.10807645454545,
            "count_val": 55
        },
        {
            "id_container_data_latest": "f2d754ba-...",
            "id_group": "4c1c81ca-...",
            "datatype": 6000,
            "source_device": "8329650b-...",
            "timestamp_seconds": 1652702400,
            "min_val": 1,
            "max_val": 1,
            "avg_val": 1,
            "count_val": 5
        }
    ],
    "_links": {
        "self": {
            "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_group%5D=4c1c81ca-1ef9-47ac-9c03-97060db9d021&filter%5Btimestamp_seconds%5D%5Bgt%5D=1652691600&filter%5Btimestamp_seconds%5D%5Blt%5D=1652778001&sort=-timestamp_seconds&page=1"
        },
        "first": {
            "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_group%5D=4c1c81ca-1ef9-47ac-9c03-97060db9d021&filter%5Btimestamp_seconds%5D%5Bgt%5D=1652691600&filter%5Btimestamp_seconds%5D%5Blt%5D=1652778001&sort=-timestamp_seconds&page=1"
        },
        "last": {
            "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_group%5D=4c1c81ca-1ef9-47ac-9c03-97060db9d021&filter%5Btimestamp_seconds%5D%5Bgt%5D=1652691600&filter%5Btimestamp_seconds%5D%5Blt%5D=1652778001&sort=-timestamp_seconds&page=1"
        }
    },
    "_meta": {
        "totalCount": 5,
        "pageCount": 1,
        "currentPage": 1,
        "perPage": 500
    }
}
```

{% endtab %}
{% endtabs %}

Because the time interval the data was requested over was more than a day in this case, the endpoint responded with hour aggregates. The precision of the data depends, i.e. the aggregation period is determined by the time interval data is requested over. The smaller the time interval, the more precise the data will be. The logic for this is shown in the schematic below.

![Logic for retrieving more precise data from down-sampled endpoint](/files/K4guLAqBmOYsKCr4DUMe)

{% hint style="info" %}
In order to reduce the resource load on our data storage, a maximum of 100 different datasets can be fetched in one request. A dataset is a unique combination of 1 group, 1 device and 1 datatype. For example, if you have 2 groups with 2 devices each reporting 2 datatypes, that’s 8 distinct datasets. This limitation can be avoided by applying further filtering, explained in the next paragraph.
{% endhint %}

### Filtering

This limitation is avoided by querying smaller chunks of time, or fewer datasets.&#x20;

&#x20;With filters you determine what data you want to retrieve.  As explained in the [previous section](/api/navigating-data) the most common onces are *id\_group* or *source\_device.* The table below provides  comprehensive overview of parameters that can be applied:

| Field                       | Description                                                             |
| --------------------------- | ----------------------------------------------------------------------- |
| id\_container\_data\_latest | UUID which describes combination of Group, Physical Device and Datatype |
| id\_group                   | UUID of Group                                                           |
| datatype                    | Datatype of stored data                                                 |
| source\_device              | UUID of Physical Device, BACE Cloud have received data from             |
| timestamp\_seconds          | Timestamp in seconds                                                    |
| min\_val                    | Minimal value                                                           |
| max\_val                    | Maximal value                                                           |
| avg\_val                    | Average value                                                           |
| count\_val                  | Count of downsampled samples                                            |

You can also request data between two timestamps to get more data, with a higher resolution.

For example you would be interested in getting temperature data.

To get more detailed information about datatype meaning, you should make GET request, to the Group endpoint with the same ID group, you have used to get data, and expand response on `dataTypes`

```
GET https://dashboard.bace-iot.com/api/v2/group/b7624b4d-...?expand=dataTypes
```

<details>

<summary>Response:</summary>

```json
{
  "id": "b7624b4d-...",
  "id_group": "b7624b4d-...",
  "label": "BacePlus-...",
  "type": "5003",
  "type_label": "Loose Device",
  "subtype": "...",
  "id_country": null,
  "created_at": 1647963043,
  "dataTypes": [
      {
          "datatype": 2070,
          "label": "Datatype 2070",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 2071,
          "label": "Datatype 2071",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 2072,
          "label": "Datatype 2072",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 2073,
          "label": "Datatype 2073",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 2100,
          "label": "Modbus Parameter 2100",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 2101,
          "label": "Modbus Parameter 2101",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 2102,
          "label": "Modbus Parameter 2102",
          "unit": "",
          "precision": 1
      },
      {
          "datatype": 5000,
          "label": "Temperature",
          "unit": "°C",
          "precision": 1
      },
      {
          "datatype": 5001,
          "label": "Relative Humidity",
          "unit": "%",
          "precision": 1
      },
      {
          "datatype": 5003,
          "label": "Presence",
          "unit": "",
          "precision": 0
      }
  ],
  "_links": {
      "self": {
          "href": "/api/v2/group/b7624b4d-..."
      },
      "index": {
          "href": "/api/v2/group/index"
      },
      "data": {
          "href": "/api/v2/data?filter[id_group]=b7624b4d-..."
      },
      "downsampled_data": {
          "href": "/api/v2/data-downsampled?filter[id_group]=b7624b4d-..."
      },
      "raw_data": {
          "href": "/api/v2/data/index?filter[id_group]=b7624b4d-..."
      }
  }
}
```

</details>

In the response you will get basic information about this group, and also information about all datatypes related to this group.

For example we want to get Temperature in °C from Group response, we can see that it is **datatype 5000**.

```json
{
    "datatype": 5000,
    "label": "Temperature",
    "unit": "°C",
    "precision": 1
}
```

Now when we know, that Temperature has datatype 5000, we can go back to Downsampled data endpoint and find id\_container\_data\_latest, matching our Temperature datatype

```json
{
    "id_container_data_latest": "8faac4b0-...,
    "id_group": "b7624b4d-...",
    "datatype": 5000,
    "source_device": "007ed6e0-...",
    "timestamp_seconds": 1647993600,
    "min_val": 27.7362060547,
    "max_val": 30.3244018555,
    "avg_val": 29.0922662866034,
    "count_val": 262
}
```

Now we can request just Temperature in °C data. We will make our request more specific. In our response from data\_downsampled endpoint we can see "timestamp\_seconds": 1647993600 - Wed Mar 23 2022 01:00:00 GMT+0100 (Central European Standard Time). Then we will try to request data for 24 hours from this timestamp.

Wed Mar 23 2022 01:00:00 GMT+0100 (Central European Standard Time) - Thu Mar 24 2022 01:00:00 GMT+0100 (Central European Standard Time)

We will make GET request to the same endpoint, but we will add two more filters and will sort received data on a timestamp\_seconds - descending.

```http
GET https://dashboard.bace-iot.com/api/v2/data-downsampled?filter[id_container_data_latest]=8faac4b0-…&filter[timestamp_seconds][gt]=1647993600&filter[timestamp_seconds][lt]=1648080000&sort=-timestamp_seconds
```

Response:

```json
{
    "items": [
        {
            "id_container_data_latest": "8faac4b0-...",
            "id_group": "b7624b4d-...",
            "datatype": 5000,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1648051140,
            "min_val": 29.9517822266,
            "max_val": 30.022277832,
            "avg_val": 29.9870300293,
            "count_val": 2
        },
        {
            "id_container_data_latest": "8faac4b0-...",
            "id_group": "b7624b4d-...",
            "datatype": 5000,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1648051080,
            "min_val": 29.9819946289,
            "max_val": 30.022277832,
            "avg_val": 30.00213623045,
            "count_val": 2
        },
        {
            "id_container_data_latest": "8faac4b0-...",
            "id_group": "b7624b4d-...",
            "datatype": 5000,
            "source_device": "007ed6e0-...",
            "timestamp_seconds": 1648051020,
            "min_val": 29.9517822266,
            "max_val": 30.022277832,
            "avg_val": 29.9870300293,
            "count_val": 2
        },
        ...
    ],
    "_links": {
        "self": {
            "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_container_data_latest%5D=8faac4b0-...&filter%5Btimestamp_seconds%5D%5Bgt%5D=1647993600&filter%5Btimestamp_seconds%5D%5Blt%5D=1648080000&sort=-timestamp_seconds&page=1"
        },
        "first": {
            "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_container_data_latest%5D=8faac4b0-...&filter%5Btimestamp_seconds%5D%5Bgt%5D=1647993600&filter%5Btimestamp_seconds%5D%5Blt%5D=1648080000&sort=-timestamp_seconds&page=1"
        },
        "last": {
            "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_container_data_latest%5D=8faac4b0-...&filter%5Btimestamp_seconds%5D%5Bgt%5D=1647993600&filter%5Btimestamp_seconds%5D%5Blt%5D=1648080000&sort=-timestamp_seconds&page=1"
        }
    },
    "_meta": {
        "totalCount": 201,
        "pageCount": 1,
js        "currentPage": 1,
        "perPage": 500
    }
}
```

Now we can find more data in the response, with 1 value per minute. But we can still see that there is some data in between, because  **"count\_val": 2**.

So to get raw data we can make last request.

```
GET https://dashboard.bace-iot.com/api/v2/data-downsampled?filter[id_container_data_latest]=8faac4b0-a971-47c6-bd16-c80b2ef99299&filter[timestamp_seconds][gt]=1648051080&filter[timestamp_seconds][lt]=1648051140&sort=-timestamp_seconds
```

In this case we are requesting data between **1648051080** - Wed Mar 23 2022 16:58:00 GMT+0100 (Central European Standard Time) and **1648051140** - Wed Mar 23 2022 16:59:00 GMT+0100 (Central European Standard Time)

Response:

```json
{
  "items": [
      {
          "id_container_data_latest": "8faac4b0-...",
          "id_group": "b7624b4d-...",
          "datatype": 5000,
          "source_device": "007ed6e0-...",
          "timestamp_seconds": 1648051122,
          "min_val": "30.022277832",
          "max_val": "30.022277832",
          "avg_val": "30.022277832",
          "count_val": 1
      },
      {
          "id_container_data_latest": "8faac4b0-...",
          "id_group": "b7624b4d-...",
          "datatype": 5000,
          "source_device": "007ed6e0-...",
          "timestamp_seconds": 1648051090,
          "min_val": "29.9819946289",
          "max_val": "29.9819946289",
          "avg_val": "29.9819946289",
          "count_val": 1
      }
  ],
  "_links": {
      "self": {
          "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_container_data_latest%5D=8faac4b0-...&filter%5Btimestamp_seconds%5D%5Bgt%5D=1648051080&filter%5Btimestamp_seconds%5D%5Blt%5D=1648051140&sort=-timestamp_seconds&page=1"
      },
      "first": {
          "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_container_data_latest%5D=8faac4b0-...&filter%5Btimestamp_seconds%5D%5Bgt%5D=1648051080&filter%5Btimestamp_seconds%5D%5Blt%5D=1648051140&sort=-timestamp_seconds&page=1"
      },
      "last": {
          "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_container_data_latest%5D=8faac4b0-...&filter%5Btimestamp_seconds%5D%5Bgt%5D=1648051080&filter%5Btimestamp_seconds%5D%5Blt%5D=1648051140&sort=-timestamp_seconds&page=1"
      }
  },
  "_meta": {
      "totalCount": 2,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 500
  }
}
```

In the response we will find raw data points.&#x20;

How to know, that it is raw data:

* We can find, that "count\_val": 1 It means there is no more data in between two timestamps
* We can also convert timestamp, for example: 1648051122, to datetime: Wed Mar 23 2022 16:58:42 GMT+0100 (Central European Standard Time). And we will see, that time is not rounded 16:58:42
* Minimal, maximal & average values are equal

## Conclusion

So to get data from aggregated data endpoint we should follow reverse logic.&#x20;

We start from getting 1 value per day. This is what downsampled\_data endpoint returns without timestamp\_seconds filters or if time interval is greater than 3 weeks.&#x20;

If you want to get more accurate data, we are able to request hourly aggregated data, by having our request interval less then 3 weeks and greater than 1 day. It should return 1 value per hour.&#x20;

Then we can make request and keep interval less than 1 day and greater than 1 hour to get data aggregated to 1 value per minute.&#x20;

To get raw data, we should make request, where requested interval would be less than 1 hour - it should return raw data

### Accessing raw data

The below example shows how the `data` endpoint can be called with a filter on *id\_group* to access that groups data:

## Access group data

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/data?filter[id_group]=0fcf513b-...`

Response will be a paginated list of datapoints that are available in the group.

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "items": [
        {
            "id_container_data_latest": "17833fcc-...",
            "id_group": "0fcf513b-...",
            "datatype": 2105,
            "source_device": "40f0462c-...",
            "timestamp_seconds": 1628774057,
            "microseconds": 965000,
            "value": 50
        },
        {
            "id_container_data_latest": "17833fcc-...",
            "id_group": "0fcf513b-...",
            "datatype": 2106,
            "source_device": "40f0462c-...",
            "timestamp_seconds": 1628774064,
            "microseconds": 275000,
            "value": 100
        },
        {
            "id_container_data_latest": "17833fcc-...",
            "id_group": "0fcf513b-...",
            "datatype": 2107,
            "source_device": "40f0462c-...",
            "timestamp_seconds": 1628774070,
            "microseconds": 575000,
            "value": 0
        }
    ],
    "_links": {
        "self": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data/index?filter%5Bid_group%5D=0fcf513b-..."
        },
        "first": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data/index?filter%5Bid_group%5D=0fcf513b-..."
        },
        "last": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data/index?filter%5Bid_group%5D=0fcf513b-..."
        },
        "next": {
            "href": "https://evalan-dev-bace-webapp.azurewebsites.net/api/v2/data/index?filter%5Bid_group%5D=30fcf513b-...&page=2"
        }
    },
    "_meta": {
        "totalCount": 3,
        "pageCount": 3,
        "currentPage": 1,
        "perPage": 500
    }
}
```

{% endtab %}

{% tab title="401: Unauthorized Request was made with invalid credentials" %}

```javascript
{
    "name": "Unauthorized",
    "message": "Your request was made with invalid credentials.",
    "code": 0,
    "status": 401,
    "type": "yii\\web\\UnauthorizedHttpException"
}
```

{% endtab %}
{% endtabs %}

From the response we see that this group has three data points from three different datatypes available. If more than 500 datapoints are available in the group the response will be paginated with latest data on top. Please refer to the Advanced Features section to learn about browsing through pages.

Note that both the `data` endpoint requires you to set a filter. Forgetting the filter will result in an error.


# Data Sessions

The following endpoint only applies to BACE GO device

{% hint style="info" %}
This endpoint in only applicable for **BACE GO**. Not sure which device you are working with? Find out [here](/reference/powering-iot-connectivity-modules).
{% endhint %}

Whenever a **BACE Go** is turned on, a Data Session is created automatically in the BACE cloud. The Data Session is automatically closed when the device is turned off.

![](/files/7qEJEOjuUcFjKJtrkMic)

The BACE API for Data Sessions allows you to:

* Get information about the Data Session
* Get information about the device reporting data
* Get all data associated with Data Session

To start getting Data Sessions data from the BACE API, you must have:

* An active User account
* A physical or virtual device (able to start/stop Data Session) provisioned and related to your project
* (Optionally) a peripheral or sensor connected to your BACE device

## How to get Data Sessions Data?

To retrieve data from a data session, two request are required:

* List all Data Sessions
* Get specific data from session
* Download full session in CSV file

### List all Data Sessions

To get list of all Data Sessions in the system available for you, you should make a GET request

<mark style="color:blue;">`GET`</mark>`https://`dashboard.bace-iot.com`/api/v2/data-session?sort=-star`

In our example we will sort Data Sessions on start time descending, such that the latest Data Sessions that was started is in the beginning of the list.

```json
{
      "items": [
          {
              "id_data_session": "86d70a1b-...",
              "id_group": "4c1c81ca-...",
              "id_person": null,
              "label": "BACE Go XXX 2022-03-30 14:04",
              "start": 1648641893,
              "end": 1648643067,
              "created_at": 1648641897,
              "created_by": null,
              "updated_at": 1648643384,
              "updated_by": null,
              "archived_at": null,
              "datapoint_count": 10,
              "isIngestionFinished": true,
              "isArchived": false,
              "_links": {
                  "self": {
                      "href": "https://dashboard.bace-iot.com/api/v2/data-session/view?id=86d70a1b-..."
                  },
                  "index": {
                      "href": "https://dashboard.bace-iot.com/api/v2/data-session/index"
                  }
              }
          },
          ...
      ]
      "_links": {
          "self": {
              "href": "https://dashboard.bace-iot.com/api/v2/data-session?sort=-start&page=1"
          },
          "first": {
              "href": "https://dashboard.bace-iot.com/api/v2/data-session?sort=-start&page=1"
          },
          "last": {
              "href": "https://dashboard.bace-iot.com/api/v2/data-session?sort=-start&page=274"
          },
          "next": {
              "href": "https://dashboard.bace-iot.com/api/v2/data-session?sort=-start&page=2"
          }
      },
      "_meta": {
          "totalCount": 5474,
          "pageCount": 274,
          "currentPage": 1,
          "perPage": 20
      },
      "expand": [
          "datatypes",
          "datatypesFilter",
          "creator",
          "updater",
          "physicalDevicesFilter",
          "physicalDevices",
          "fromDevice",
          "group",
          "dataIds"
      ],
      "labels": {
          "group.label": "Group",
          "person.label": "Person",
          "person.objectLink": "Person",
          "sourceDevicesString": "Source Devices",
          "datatypesString": "Datatypes",
          "ingestionStatusString": "Ingestion",
          "archivingStatusString": "Archived"
      }
    }

```

In the response you will get basic information about all Data Sessions. You have access to the following fields:

| Field               | Description                                                                                                                                        |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| id\_data\_session   | UUID of the Data session                                                                                                                           |
| id\_group           | UUID of the Group device is in. To get more information use: expand=group                                                                          |
| id\_person          | UUID of the Person related to the Datasession                                                                                                      |
| label               | Descriptive label for the datasession                                                                                                              |
| start               | Data session start timestamp in seconds                                                                                                            |
| end                 | Data session end timestamp in seconds. null - if Data session is active and not stopped                                                            |
| created\_at         | Timestamp in seconds, when Data sessions record have been created                                                                                  |
| created\_by         | UUID of the User, who have created Data session. For Data session started from the device - null. To get more information use: expand=creator      |
| updated\_at         | Timestamp in seconds, when Data sessions record have been last updated                                                                             |
| updated\_by         | UUID of the User, who have last updated Data session. For Data session updated from the device - null. To get more information use: expand=updater |
| archived\_at        | Timestamp in seconds, when Data session have been archived                                                                                         |
| datapoint\_count    | Total datapoint count in the Data session                                                                                                          |
| isIngestionFinished | Boolean describing data ingestion process                                                                                                          |
| isArchived          | Boolean describing, if archiving of Data session have been finished                                                                                |

### Get data from Data Session

To get specific data associated with a Data Session. You should make a GET request from the `data-downsampled` endpoint, specifiying the session ID.

<mark style="color:blue;">`GET`</mark>` ``https://dashboard.bace-iot.com/api/v2/data-downsampled?filter[id_data_session]=ID_DATA_SESSION`

Example response:

```json
{
  "items": [
      {
          "id_container_data_latest": "c1dafb46-...",
          "id_group": "4c1c81ca-...",
          "datatype": 5205,
          "source_device": "6b88b4df-...",
          "timestamp_seconds": 1648641939.995,
          "min_val": 3.95,
          "max_val": 3.95,
          "avg_val": 3.95,
          "count_val": 1
      },
      {
          "id_container_data_latest": "c1dafb46-...",
          "id_group": "4c1c81ca-...",
          "datatype": 5205,
          "source_device": "6b88b4df-...",
          "timestamp_seconds": 1648642239.995,
          "min_val": 3.94,
          "max_val": 3.94,
          "avg_val": 3.94,
          "count_val": 1
      },
      ...
  ],
  "_links": {
      "self": {
          "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_data_session%5D=86d70a1b-...&page=1"
      },
      "first": {
          "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_data_session%5D=86d70a1b-...&page=1"
      },
      "last": {
          "href": "https://dashboard.bace-iot.com/api/v2/data-downsampled?filter%5Bid_data_session%5D=86d70a1b-...&page=1"
      }
  },
  "_meta": {
      "totalCount": 10,
      "pageCount": 1,
      "currentPage": 1,
      "perPage": 500
  }
}
```

| Field                       | Description                                                             |
| --------------------------- | ----------------------------------------------------------------------- |
| id\_container\_data\_latest | UUID which describes combination of Group, Physical Device and Datatype |
| id\_group                   | UUID of Group                                                           |
| datatype                    | Datatype of stored data                                                 |
| source\_device              | UUID of Physical Device, BACE Cloud have received data from             |
| timestamp\_seconds          | Timestamp in seconds                                                    |
| min\_val                    | Minimal value                                                           |
| max\_val                    | Maximal value                                                           |
| avg\_val                    | Average value                                                           |
| count\_val                  | Count of downsampled samples                                            |

If data is downsampled, the field count\_val is greater than 1. In this case, you can also request data between 2 timestamps to get data with a higher resolution, i.e. more datapoints.

More information about [downsampling mechanism ](/api/accessing-data#downsampling-mechanism)and how to use [data-downsampled endpoint](/api/accessing-data#using-downsampled_data-endpoint)

### Download data in .csv file

To download the complete Data Session in a CSV file, you should make GET request from the download-csv endpoint.

<mark style="color:blue;">`GET`</mark>` ``https://dashboard.bace-iot.com/api/v2/data-session/ID_DATA_SESSION/download-csv`


# Commanding Connectivity Modules

You can instruct your devices to run certain preconfigured functions

You can send commands to Connectivity Modules to perform certain actions. Some commands like Restart, Ping are valid across all Connectivity modules, and some commands are only applicable to certain Connectivity Modules and applications running on them.

You will always use `physical-devices` endpoint to send these instructions to Connectivity Modules so you need to retrieve corresponding `id_physical_device` using [Physical device endpoint](/api/navigating-data#navigating-physical-devices).&#x20;

### List of Standard commands

The following standard commands below works with corresponding Connectivity Modules regardless of the application it is running.

<table><thead><tr><th width="175">Endpoint Name</th><th>Description</th><th width="287">Modules</th></tr></thead><tbody><tr><td><code>ping</code></td><td>It will ping the Connectivity Module</td><td>GO/CORE/PLUS</td></tr><tr><td><code>restart</code></td><td>Restarts Connectivity Module</td><td>GO/CORE/PLUS</td></tr><tr><td><code>self-test</code></td><td>Provides a list of information about the module</td><td>GO/CORE/PLUS</td></tr><tr><td><code>request-measurement</code></td><td>Forces Module to request measurement from all assets connected to it</td><td>GO/CORE/PLUS</td></tr><tr><td><code>wifi</code></td><td>Scan, connect or disconnect from a WiFi Access point</td><td>PLUS/CORE</td></tr></tbody></table>

## Ping IoT connectivity module

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/ping`

Pinging IoT connectivity module will tell if it is online or offline

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

{% tabs %}
{% tab title="200: OK Succesful Ping" %}

```json
{
    "status": 200,
    "payload": {
        "data": "pong",
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="404: Not Found Unsuccesful ping (offline device)" %}

```javascript
{
    "name": "Not Found",
    "message": "The operation Ping failed because the requested device isn't online or does not support this operation.",
    "code": 0,
    "status": 404
}
```

{% endtab %}
{% endtabs %}

## Restart IoT connectivity module

<mark style="color:green;">`POST`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/restart`

Sends a command to restart IoT connectivity module

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

{% tabs %}
{% tab title="200: OK Successful Restart" %}

```json
{
    "status": 200,
    "payload": {
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="404: Not Found Unsuccessful restart" %}

```json
{
    "name": "Not Found",
    "message": "The requested record with id 087dbbca-4efd-47df-949d-0cb8fcf61c5c could not be found or is inaccessible",
    "code": 0,
    "status": 404
}
```

{% endtab %}
{% endtabs %}

## Performs Self-test for IoT connectivity module

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/status`

Sends a command to perform self-test for IoT connectivity module. Response could help support troubleshooting connectivity related problems.

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

{% tabs %}
{% tab title="200: OK Successful Selftest" %}

```json
{
    "status": 200,
    "payload": {
        "isGnssOk": true,
        "isModemConnected": true,
        "isInputVoltageOk": true,
        "inputVoltage": 11.671,
        "isAteccOk": false,
        "ModemInfo": "+CPSI: LTE CAT-M1,Online,204-08,0x7EF7,18189068,113,EUTRAN-BAND20,6400,3,3,-16,-98,-66,10\r\n",
        "WifiInfo": "1c3bf37aee5a,9,-44",
        "EthernetInfo": "NA",
        "SatsInView": 12,
        "SatsInUse": 8,
        "uptime": 12582,
        "minFreeHeap": 4065391,
        "freeHeap": 4088163,
        "internalFreeHeap": 60987,
        "minInternalFreeHeap": 50231,
        "externalFreeHeap": 4027563,
        "minExternalFreeHeap": 4015283,
        "nvsUsedEntries": 165,
        "nvsFreeEntries": 7899,
        "spiffsUsage": 502,
        "spiffsTotal": 11615276,
        "isSpiffsOk": true,
        "resetCause": "SW",
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="404: Not Found Unsuccessful selftest" %}

```json
{
    "name": "Not Found",
    "message": "The operation SelfTest failed because the requested device isn't online or does not support this operation.",
    "code": 0,
    "status": 404
}
```

{% endtab %}
{% endtabs %}

## Request measurement from connected assets

<mark style="color:orange;">`PUT`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/request-measurement`

Instructs IoT connectivity module to request the latest measurements from all connected assets or sensors.

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

{% tabs %}
{% tab title="200: OK Successful" %}

```json
{
    "status": 200,
    "payload": {
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="404: Not Found Unsuccessful" %}

```json
{
    "name": "Not Found",
    "message": "The operation RequestMeasurement failed because the requested device isn't online or does not support this operation.",
    "code": 0,
    "status": 404
}
```

{% endtab %}
{% endtabs %}

## Scan nearby WiFi Access Points

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/wifi`

WiFi endpoint is used for retrieving nearby WiFi Access points.

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    "status": 200,
    "payload": {
        "wifiAccessPoints": [
            {
                "ssid": "",
                "macAddress": "223bf37aee5a",
                "signalStrength": -42,
                "channel": 9
            },
            {
                "ssid": "",
                "macAddress": "223bf37aed1c",
                "signalStrength": -68,
                "channel": 9
            },
            {
                "ssid": "billa TC",
                "macAddress": "f099bf06c428",
                "signalStrength": -72,
                "channel": 6
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "342cc45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Ziggo",
                "macAddress": "362c945a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Saskia vd Meijden-Bessems",
                "macAddress": "362cb45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "",
                "macAddress": "362cd45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "0aa030d703d0",
                "signalStrength": -75,
                "channel": 6
            },
            {
                "ssid": "Mein7490",
                "macAddress": "1ced6fe4dc05",
                "signalStrength": -75,
                "channel": 11
            },
            {
                "ssid": "",
                "macAddress": "0aa030d703d3",
                "signalStrength": -76,
                "channel": 6
            },
            {
                "ssid": "",
                "macAddress": "8c8580792c71",
                "signalStrength": -77,
                "channel": 6
            },
            {
                "ssid": "FBI",
                "macAddress": "a2c9eb1cfee7",
                "signalStrength": -79,
                "channel": 3
            },
            {
                "ssid": "Mein7490",
                "macAddress": "3810d5279801",
                "signalStrength": -81,
                "channel": 11
            },
            {
                "ssid": "FBI-Guest",
                "macAddress": "a6c9eb1cfee7",
                "signalStrength": -82,
                "channel": 3
            },
            {
                "ssid": "",
                "macAddress": "9cc9eb1cfee7",
                "signalStrength": -83,
                "channel": 3
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "0aa030d70420",
                "signalStrength": -88,
                "channel": 1
            },
            {
                "ssid": "",
                "macAddress": "0aa030d70423",
                "signalStrength": -88,
                "channel": 1
            },
            {
                "ssid": "Mein7490",
                "macAddress": "ccce1ef8e3ee",
                "signalStrength": -88,
                "channel": 11
            },
            {
                "ssid": "",
                "macAddress": "9cc9eb1ca8c5",
                "signalStrength": -89,
                "channel": 3
            },
            {
                "ssid": "FBI",
                "macAddress": "a2c9eb1ca8c5",
                "signalStrength": -89,
                "channel": 3
            },
            {
                "ssid": "FBI-Guest",
                "macAddress": "a6c9eb1ca8c5",
                "signalStrength": -90,
                "channel": 3
            },
            {
                "ssid": "Yilanci",
                "macAddress": "98ded0a4674d",
                "signalStrength": -91,
                "channel": 11
            },
            {
                "ssid": "DIRECT-4E-HP ENVY 4520 series",
                "macAddress": "48ba4e13d54f",
                "signalStrength": -93,
                "channel": 6
            }
        ],
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="501: Not Implemented " %}

```javascript
{
    "status": 501,
    "payload": {
        "result": "failed",
        "cause": "Wifi disabled"
    }
}
```

{% endtab %}
{% endtabs %}

## Connect to a WiFi Access Point

<mark style="color:orange;">`PUT`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/wifi`

WiFi endpoint is used for connecting to nearby WiFi Access point.

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

#### Request Body

| Name                                   | Type   | Description      |
| -------------------------------------- | ------ | ---------------- |
| ssid<mark style="color:red;">\*</mark> | string | name of the ssid |
| password                               | string | test             |

{% tabs %}
{% tab title="200: OK Successful response returning SSIDs" %}

```json
{
    "status": 200,
    "payload": {
        "wifiAccessPoints": [
            {
                "ssid": "",
                "macAddress": "223bf37aee5a",
                "signalStrength": -42,
                "channel": 9
            },
            {
                "ssid": "",
                "macAddress": "223bf37aed1c",
                "signalStrength": -68,
                "channel": 9
            },
            {
                "ssid": "billa TC",
                "macAddress": "f099bf06c428",
                "signalStrength": -72,
                "channel": 6
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "342cc45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Ziggo",
                "macAddress": "362c945a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Saskia vd Meijden-Bessems",
                "macAddress": "362cb45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "",
                "macAddress": "362cd45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "0aa030d703d0",
                "signalStrength": -75,
                "channel": 6
            },
            {
                "ssid": "Mein7490",
                "macAddress": "1ced6fe4dc05",
                "signalStrength": -75,
                "channel": 11
            },
            {
                "ssid": "",
                "macAddress": "0aa030d703d3",
                "signalStrength": -76,
                "channel": 6
            },
            {
                "ssid": "",
                "macAddress": "8c8580792c71",
                "signalStrength": -77,
                "channel": 6
            },
            {
                "ssid": "FBI",
                "macAddress": "a2c9eb1cfee7",
                "signalStrength": -79,
                "channel": 3
            },
            {
                "ssid": "Mein7490",
                "macAddress": "3810d5279801",
                "signalStrength": -81,
                "channel": 11
            },
            {
                "ssid": "FBI-Guest",
                "macAddress": "a6c9eb1cfee7",
                "signalStrength": -82,
                "channel": 3
            },
            {
                "ssid": "",
                "macAddress": "9cc9eb1cfee7",
                "signalStrength": -83,
                "channel": 3
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "0aa030d70420",
                "signalStrength": -88,
                "channel": 1
            },
            {
                "ssid": "",
                "macAddress": "0aa030d70423",
                "signalStrength": -88,
                "channel": 1
            },
            {
                "ssid": "Mein7490",
                "macAddress": "ccce1ef8e3ee",
                "signalStrength": -88,
                "channel": 11
            },
            {
                "ssid": "",
                "macAddress": "9cc9eb1ca8c5",
                "signalStrength": -89,
                "channel": 3
            },
            {
                "ssid": "FBI",
                "macAddress": "a2c9eb1ca8c5",
                "signalStrength": -89,
                "channel": 3
            },
            {
                "ssid": "FBI-Guest",
                "macAddress": "a6c9eb1ca8c5",
                "signalStrength": -90,
                "channel": 3
            },
            {
                "ssid": "Yilanci",
                "macAddress": "98ded0a4674d",
                "signalStrength": -91,
                "channel": 11
            },
            {
                "ssid": "DIRECT-4E-HP ENVY 4520 series",
                "macAddress": "48ba4e13d54f",
                "signalStrength": -93,
                "channel": 6
            }
        ],
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="501: Not Implemented Unsuccessful response from a WiFi disabled device" %}

```javascript
{
    "status": 501,
    "payload": {
        "result": "failed",
        "cause": "Wifi disabled"
    }
}
```

{% endtab %}
{% endtabs %}

## Disconnects from the current WiFi Access Point

<mark style="color:red;">`DELETE`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/wifi`

Delete method will disconnect gateway from the WiFi Access point

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    "status": 200,
    "payload": {
        "wifiAccessPoints": [
            {
                "ssid": "",
                "macAddress": "223bf37aee5a",
                "signalStrength": -42,
                "channel": 9
            },
            {
                "ssid": "",
                "macAddress": "223bf37aed1c",
                "signalStrength": -68,
                "channel": 9
            },
            {
                "ssid": "billa TC",
                "macAddress": "f099bf06c428",
                "signalStrength": -72,
                "channel": 6
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "342cc45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Ziggo",
                "macAddress": "362c945a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Saskia vd Meijden-Bessems",
                "macAddress": "362cb45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "",
                "macAddress": "362cd45a3d22",
                "signalStrength": -75,
                "channel": 1
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "0aa030d703d0",
                "signalStrength": -75,
                "channel": 6
            },
            {
                "ssid": "Mein7490",
                "macAddress": "1ced6fe4dc05",
                "signalStrength": -75,
                "channel": 11
            },
            {
                "ssid": "",
                "macAddress": "0aa030d703d3",
                "signalStrength": -76,
                "channel": 6
            },
            {
                "ssid": "",
                "macAddress": "8c8580792c71",
                "signalStrength": -77,
                "channel": 6
            },
            {
                "ssid": "FBI",
                "macAddress": "a2c9eb1cfee7",
                "signalStrength": -79,
                "channel": 3
            },
            {
                "ssid": "Mein7490",
                "macAddress": "3810d5279801",
                "signalStrength": -81,
                "channel": 11
            },
            {
                "ssid": "FBI-Guest",
                "macAddress": "a6c9eb1cfee7",
                "signalStrength": -82,
                "channel": 3
            },
            {
                "ssid": "",
                "macAddress": "9cc9eb1cfee7",
                "signalStrength": -83,
                "channel": 3
            },
            {
                "ssid": "Ziggo9025459",
                "macAddress": "0aa030d70420",
                "signalStrength": -88,
                "channel": 1
            },
            {
                "ssid": "",
                "macAddress": "0aa030d70423",
                "signalStrength": -88,
                "channel": 1
            },
            {
                "ssid": "Mein7490",
                "macAddress": "ccce1ef8e3ee",
                "signalStrength": -88,
                "channel": 11
            },
            {
                "ssid": "",
                "macAddress": "9cc9eb1ca8c5",
                "signalStrength": -89,
                "channel": 3
            },
            {
                "ssid": "FBI",
                "macAddress": "a2c9eb1ca8c5",
                "signalStrength": -89,
                "channel": 3
            },
            {
                "ssid": "FBI-Guest",
                "macAddress": "a6c9eb1ca8c5",
                "signalStrength": -90,
                "channel": 3
            },
            {
                "ssid": "Yilanci",
                "macAddress": "98ded0a4674d",
                "signalStrength": -91,
                "channel": 11
            },
            {
                "ssid": "DIRECT-4E-HP ENVY 4520 series",
                "macAddress": "48ba4e13d54f",
                "signalStrength": -93,
                "channel": 6
            }
        ],
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="501: Not Implemented " %}

```javascript
{
    "status": 501,
    "payload": {
        "result": "failed",
        "cause": "Wifi disabled"
    }
}
```

{% endtab %}
{% endtabs %}

### List of Application Specific Commands

For some projects, a project specific application is developed to control connected assets in a certain way. Some examples of these types of Application Specific Commands are:

* Instructing Connectivity Module to run a measurement routine, do some math calculations and control relays connected to it.
* Send counter reset command to a flow meter connected to Connectivity module via RS232.

## Reset main counter

<mark style="color:orange;">`PUT`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/:id/reset-main-counter`

Command used to restart flow meter main counter

{% tabs %}
{% tab title="200: OK Successful request" %}

```javascript
{
    "status": "200",
}
```

{% endtab %}

{% tab title="400: Bad Request Unsuccessful request" %}

```javascript
{
    "name": "Bad Request",
    "message": "This device is offline or does not support this method.",
    "code": 0,
    "status": 400,
    "type": "yii\\web\\BadRequestHttpException"
}
```

{% endtab %}
{% endtabs %}

## Reset daily counter

<mark style="color:orange;">`PUT`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/:id/reset-daily-counter`

Command used to restart flow meter daily counter

{% tabs %}
{% tab title="200: OK Successful request" %}

```javascript
{
    "status": "200",
}
```

{% endtab %}

{% tab title="400: Bad Request Unsuccessful request" %}

```javascript
{
    "name": "Bad Request",
    "message": "This device is offline or does not support this method.",
    "code": 0,
    "status": 400,
    "type": "yii\\web\\BadRequestHttpException"
}
```

{% endtab %}
{% endtabs %}


# Commanding Modbus Devices

We'll explain how to command Modbus devices in a few steps

## Introduction

The BACE IoT Platform allows you to command modbus devices through writable modbus registers. This capability allows control over several device functions such as starting a motor pump, adjusting its speed, or updating a solar inverter's schedule. Refer to the Modbus device manual for understanding the appropriate registers to write to and the correct values to achieve the desired action.

Before writing to modbus registers via the BACE IoT Platform, please ensure:

1. The Modbus device is onboarded onto the BACE Gateway and actively sending measurements.
2. You have the requisite `datatype` for writing to the corresponding modbus device and registers.

If you have not onboarded your Modbus device yet, please visit [How To Onboard Modbus Devices](/bace-panel/how-to-onboard-modbus-devices)  on how to do so.

Once your device is properly set up, you must obtain the corresponding `datatype` for your device. As also explained in [Accessing Data](/api/accessing-data), there are multiple ways to retrieve all measurements and their groups. Below is an example API request to fetch all datatypes and their latest values using `id_physical_device` endpoint

## Get all datatypes and their latest data of a gateway

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}?expand=group.latestData`

Returns all the latest measurements collected by the gateway

#### Query Parameters

| Name                                 | Type   | Description          |
| ------------------------------------ | ------ | -------------------- |
| id<mark style="color:red;">\*</mark> | String | id\_physical\_device |

{% tabs %}
{% tab title="200: OK " %}

{% endtab %}
{% endtabs %}

## Writing to a Single Register

To write to a Modbus device, use the ModbusWrite endpoint. This process requires you to provide the `datatype` number and the desired value in the payload.

<table><thead><tr><th width="161">parameter</th><th>description</th></tr></thead><tbody><tr><td>datatype</td><td>Each modbus register has an index called <code>datatype</code> assigned by the gateway. The datatype is used for reading to and writing from modbus registers.</td></tr><tr><td>value</td><td>this is the value you want to write to the modbus register</td></tr></tbody></table>

## Using modbus-write Endpoint

The modbus-write endpoint is your interaction point to command a device. The payload must include the `datatype`number and the desired value for execution.

## Write to a Modbus Register

<mark style="color:orange;">`PUT`</mark> `https://dashboard.bace-iot.com/api/v2/physical-device/{id}/modbus-write`

modbus-write endpoint is used for writing to modbus register(s)

#### Path Parameters

| Name                                 | Type   | Description                    |
| ------------------------------------ | ------ | ------------------------------ |
| id<mark style="color:red;">\*</mark> | string | Gateway's id\_physical\_device |

#### Request Body

| Name                                       | Type      | Description                     |
| ------------------------------------------ | --------- | ------------------------------- |
| datatype<mark style="color:red;">\*</mark> | int       | datatype of the modbus register |
| value<mark style="color:red;">\*</mark>    | int/float | provide the value               |

{% tabs %}
{% tab title="200: OK Successful response" %}

```json
{
    "status": 200,
    "payload": {
        "result": "success"
    }
}
```

{% endtab %}

{% tab title="400: Bad Request Unsuccessful response" %}

{% endtab %}
{% endtabs %}

Here is an example payload for writing to a single modbus register.

```
{
    "datatype": 2100,
    "value": 15
}
```

## Writing to Multiple Registers

The endpoint can execute a write action for multiple registers simultaneously. This process requires providing all `datatype`s and their corresponding values within the same payload as an array. Below is an example payload to set schedule for a solar inverter:

```
[
  {
    "datatype": 2100,
    "value": 13
  },
  {
    "datatype": 2101,
    "value": 20
  },
  {
    "datatype": 2102,
    "value": 21
  }
]
```


# Accessing Events

## Event Endpoint

The `event` endpoint provides information on events that have occurred in the BACE IoT platform. It returns a list of events and event details such as type, time, and description.

`event` endpoint has potential to return all events occurred in the system so it is strongly suggested to use filters explained in [Advanced Features](/api/advanced-features)

## Retrieve gateway and cloud events&#x20;

<mark style="color:blue;">`GET`</mark> `https://dashboard.bace-iot.com/api/v2/event`

Use this endpoint to get all events from all gateways or particular devices.

#### Query Parameters

| Name                    | Type   | Description                     |
| ----------------------- | ------ | ------------------------------- |
| filter\[source\_device] |        | filter by source device         |
| filter\[id\_event]      |        | filter by id\_event             |
| sort                    | String | sorting events by specification |

{% tabs %}
{% tab title="200: OK The request was successful and the events were returned" %}

```json
{
    "items": [
        {
            "id_event": 2204754,
            "id_group": "19a2d526-6219-4431-ab92-e6a1c091a5db",
            "source_device": "369e32b8-0db3-4f98-82d7-3bbb0c909b67",
            "from_device": 1,
            "event_type": "208",
            "event_type_label": "208 - Cloud connectivity changed",
            "event_type_description": "",
            "occurred_at": 1674828349,
            "value": "2",
            "datatype": null,
            "event_value_label": "Modem",
            "event_value_description": "Cellular connection in use"
        }
}
```

{% endtab %}

{% tab title="401: Unauthorized The request requires authentication and the provided credentials were invalid" %}

{% endtab %}
{% endtabs %}

### Response

The response will be a JSON array of events, with each event having the following attributes:

* **id\_event:** a unique identifier for the event.
* **id\_group**: the identifier of the group to which the event's source device belongs.
* **source\_device**: the identifier of the device that generated the event.
* **from\_device**: an identifier indicating whether the event was generated by a device or the cloud.
* **event\_type**: the type of event, represented by a numerical code.
* **event\_type\_label**: a human-readable label for the event type.
* **event\_type\_description**: a description of the event type.
* **occurred\_at**: the time at which the event occurred, represented as a Unix timestamp.
* **value**: the value associated with the event. Some events have multiple values that inform different situations. Always refer to event\_value\_label and event\_value\_description to understand what it is.
* **datatype**: the data type of the `value` field.
* **event\_value\_label**: a human-readable label for the event value.
* **event\_value\_description**: a description of the event value.


# 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.&#x20;
* 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

```json
"_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.

<mark style="color:blue;">`GET`</mark>` ``https://dashboard.bace-iot.com/api/v2/physical-device`

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

{% hint style="info" %}
Expand options array is available only in collection endpoint, but can be used in the same way on collection and singleton endpoints
{% endhint %}

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.

<mark style="color:blue;">`GET`</mark>` ``https://dashboard.bace-iot.com/api/v2/physical-device/0235e44c-…?expand=group,parent,parent.group`

Example response:

```json
{
    "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:

```json
{
  "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.&#x20;

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

**Request body**

```json
{
    "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.

## Links

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:

<mark style="color:blue;">`DELETE`</mark>` ``https://dashboard.bace-iot.com/api/v2/physical-device/04771e4c-…/zwave-node`

**Example response**

```json
{
  "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"
    }
  }
}
```

<table><thead><tr><th width="203.6423406098108">Fields</th><th>Description</th></tr></thead><tbody><tr><td>fromCloud</td><td>Is response User got from IoT Hub</td></tr><tr><td>message</td><td>Message generated by BACE Cloud</td></tr><tr><td>routeToPollEvents</td><td>This is endpoint, User can use to listen to get result of asynchronous action</td></tr><tr><td>tips</td><td>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.</td></tr></tbody></table>


# BACE Webhooks

How to connect BACE to your IoT Application using Webhooks

## Introduction

Webhooks are developed to send events to your application(s). The difference with classical API is that a webhook is used to actively push data to an external endpoint, instead of having the third-party poll for data.

In this chapter, we'll give a walkthrough on how to use Webhooks for measurements or events and provide some tips on how to use them most effectively for your application. A general introduction about how to use the BACE Webhooks is given in

## How to use BACE Webhooks

Webhooks could be used to synchronize your asset measurements and events to your system. These measurements and events could be stored in your database to be ingested by your IoT application.&#x20;

The BACE Webhook supports HTTPS URLs, and a static authentication header can be used to publish responses to subscribers. The data is sent by HTTPS Post requests.

For creating a new webhook using BACE Panel, please use following steps in [Creating Webhooks](/bace-panel/creating-webhooks)

## Sending Measurements as a Webhook

Measurements from your assets are forwarded as a webhook response in the order they are received by the [IoT Connector](/system-overview#iot-connector). Depending on the sampling rate of IoT connector, you will receive a response for any new measurements retrieved from your assets.

{% hint style="warning" %}
If the IoT Connector cannot retrieve any new measurements from the device, for example when your asset is offline, you will not receive a webhook.
{% endhint %}

### Example of one measurement

Here is an example webhook message for an IoT Connector with one measurement (aka datatype):

```json
[{    
  "timestamp": 1634730271645,
  "timestamp_seconds": 1634730271.645,    
  "timestamp_changed": 1634730271645,    
  "datatype": 5000,    
  "value": 29.5489501953125,    
  "relations": {      
      "id_container": "caff51ce-d6e4-4329-abde-8b2a0dbc733d",      
      "id_group": "3cf26834-777e-4c46-ae0c-352de3509871",      
      "source_device": "16d7706e-b429-4778-8f8c-cfd6e2050649",      
      "id_container_data_latest": "46e6afab-f9d5-446d-bc75-c31b47e49be4"    
      },    
  "label": "Temperature",    
  "unit": "°C",    
  "icon": "fas fa-thermometer-three-quarters"  
}] 
```

Here is the breakdown of all attributes in the webhook response:

* **Timestamp –** Timestamp in milliseconds. This is the exact time of the measurement performed in the field.
* **Timestamp\_seconds –** Timestamp in seconds, same as above.
* **Timestamp\_change –** Timestamp in milliseconds. This is the time the value was last changed. For example, if the last value is 50, and the previous value is also 50, we don't change the timestamp from the first time we saw "50". Only when the value changes by >0.01 (in either direction) the `timestamp_changed` value updates to the time of that measurement.
* **Datatype:** Datatype of stored data. Each measurement type has a predefined or user configured datatype. An IoT Connectivity Module may be reporting the same data type (i.e. 5000 - Temperature) from many customer assets connected to it (i.e. Modbus #1 - Zwave #1)
* **Value:** Value of the measurement.
* **Relations:** Shows the relationship of the measurement:
  * **id\_container:** Unique id of the container. Each IoT Connectivity Module will have a unique `id_container`.&#x20;
  * **id\_group:** Unique id of the group. Each IoT Connectivity Module will have a unique `id_group`. This field could be used to interpret which IoT Connectivity Module has sent the measurement.
  * **source\_device:** Unique id of the IoT Connectivity Module or your asset sending the measurement. Each IoT Connector and Zwave device have their own unique ids. This field could be used to interpret which IoT Connectivity Module has sent the measurement. This value is same as `id_physical_device` explained in [physical-device endpoint](/api/navigating-data#navigating-physical-devices). The IoT Communication Module has a sticker that matches with `label` attribute in the physical-device endpoint's response.
  * **id\_container\_data\_latest:** id\_container of the latest data for this measurement. This could be useful for particular API calls if you want to request a specific measurement.
* **label:** Predefined or user configurable label of the measurement. You can use generic expressions like "Temperature" or use it in a more descriptive way like "SolarConverter-FaultCode"
* **unit:** Predefined or user configurable unit of the measurement.
* **icon:** User configurable field. This field could be used as a hint to your frontend what icon to use for a given datatype when displaying status indicators.&#x20;

Each webhook response should contain measurements for one IoT Connector which could be differentiated by its unique `group_id`.

### Example of Multiple Measurements

When your IoT Connector is configured to retrieve multiple measurements (aka datatypes) from your asset, you can see many data points in one webhook response. The example below shows a device with three different data types in the same response.

```json
[
  {
    "timestamp": 1655381927834,
    "timestamp_seconds": 1655381927.834,
    "timestamp_changed": 1655381927834,
    "datatype": 2185,
    "value": 280,
    "relations": {
      "id_container": "e3ebb57a-d1b3-49ef-a5f3-f84307822b78",
      "id_group": "3f813212-63aa-49b5-aa71-c95acbf14ad6",
      "source_device": "1d551a5c-36e7-400c-a6ed-490bcc3815fa",
      "id_container_data_latest": "379c101e-0e40-4f55-8f09-d5f94d1ab2ec"
    },
    "label": "WTW-ZehnderE300-OutletTemperature",
    "unit": null,
    "icon": null
  },
  {
    "timestamp": 1655382346354,
    "timestamp_seconds": 1655382346.354,
    "timestamp_changed": 1655358046192,
    "datatype": 10000,
    "value": 165.91600036621094,
    "relations": {
      "id_container": "e3ebb57a-d1b3-49ef-a5f3-f84307822b78",
      "id_group": "3f813212-63aa-49b5-aa71-c95acbf14ad6",
      "source_device": "1d551a5c-36e7-400c-a6ed-490bcc3815fa",
      "id_container_data_latest": "543afeaa-8258-4129-8840-951e301b00eb"
    },
    "label": "Consumption 1",
    "unit": "kWh",
    "icon": null
  },
  {
    "timestamp": 1655382351594,
    "timestamp_seconds": 1655382351.594,
    "timestamp_changed": 1655382351594,
    "datatype": 10007,
    "value": 5.359999656677246,
    "relations": {
      "id_container": "e3ebb57a-d1b3-49ef-a5f3-f84307822b78",
      "id_group": "3f813212-63aa-49b5-aa71-c95acbf14ad6",
      "source_device": "6667e971-af9d-4027-8b49-2c5ca2e725b9",
      "id_container_data_latest": "10c0eb14-18fe-48aa-a1ab-c90a9348c45a"
    },
    "label": "Electrical Meter",
    "unit": "kWh",
    "icon": null
  }
]
```

Let's breakdown the webhook response above. From the array length, it is understood that IoT Connector with `"id_group": "3f813212-63aa-49b5-aa71-c95acbf14ad6"`has sent three measurements.

The first measurement has a descriptive label `"label": "WTW-ZehnderE300-OutletTemperature",`  which includes asset model & name and name of the value. The report value is  `"value": 280` per the response.

The second measurement is for a measurement called `"label": "Consumption 1"`, and measurement is `"value": 165.91600036621094` in `"unit": "kWh"`. First and second measurements have the same `id_group` and `source_device.`

Third measurement ia veryom a `"label": "Electrical Meter"` connected to IoT Connector. However, the third measurement is received from Z-wave plug so that's why it has a different `source_device` than the first two measurements.

### Compact Format Overview

Certain gateways, such as BACE Go, can transmit a considerable volume of data, potentially exceeding 1MB in payload size when employing the standard format. Some backend services may find it overwhelming to process such large payloads.&#x20;

Compact format is optimized to transmit essential data without verbosity. It's a way to retain crucial information in a concise manner to reduce payload size.

```json
{
  "groups": {
    "b85dda65-1a26-49ac-a049-5e37e3dd3cf7": {
      "devices": {
        "fac7670d-a64d-4071-a4c0-a01e23d4c8e3": {
          "datatypes": {
            "2100": {
              "label": "Voltage",
              "id_container_data_latest": "d75b196e-da34-4886-a2b3-9aa7ac7b6928",
              "data": [
                [
                  1692781843650,
                  230.5
                ]
              ]
          }
        }
      }
    }
  }
}
```

Here is the breakdown of all attributes in the webhook response:

* **groups –** Unique id of the group. Each IoT Connectivity Module have a unique `id_group`. This field could be used to interpret which IoT Connectivity Module has sent the measurement.
* **devices:** Unique id of the IoT Connectivity Module or your asset sending the measurement. Each IoT Connector and Zwave device have their own unique ids. This field could be used to interpret which IoT Connectivity Module has sent the measurement. This value is same as `id_physical_device` explained in [physical-device endpoint](/api/navigating-data#navigating-physical-devices). The IoT Communication Module has a sticker that matches with `label` attribute in the physical-device endpoint's response.
* **datatypes:** Datatype of stored data. Each measurement has a predefined or user configured datatype. If the event is related to a specific data type, it will be reported in this attribute. A good example is for Modbus Read-error which might occur when IoT Connector is trying to poll information from a specific modbus register assigned to a data type. Each nested datatype has three attributes:
  * **label:** A label can either be predefined or user-defined. It can be generic like "Temperature" or descriptive like "SolarConverter-FaultCode"
  * **id\_container\_data\_latest:** id\_container of the latest data for this measurement. This could be useful for particular API calls if you want to request a specific measurement.
  * **data:** An array where the first item indicates the timestamp (in milliseconds) of the measurement, and the second item denotes its value

## Sending Events as a Webhook

Like measurements, any events from your assets, IoT Communication module or IoT connector are forwarded as a webhook response to your HTTP address.&#x20;

Here is an example webhook message for an IoT Connector with one measurement:

```json
[
  {
    "id_event": 299663,
    "id_group": "4df124e4-160d-46cf-b19c-3411e6280e3c",
    "source_device": "e67c9edc-13ab-48cc-8802-765f6d185d52",
    "from_device": 1,
    "event_type": "202",
    "event_type_label": "202 - Reset Cause on boot",
    "occurred_at": 1660223629,
    "value": "1",
    "datatype": null,
    "event_value_label": "ESP_RST_POWERON",
    "event_value_description": "Reset due to power-on event",
  }
]
```

Here is the breakdown of all attributes in the webhook response:

* **id\_event –** Unique id of the event.
* **id\_group –** Unique id of the group. Each IoT Connectivity Module have a unique `id_group`. This field could be used to interpret which IoT Connectivity Module has sent the measurement.
* **source\_device –** Unique id of the IoT Connectivity Module or your asset sending the event. Each IoT Connector and Zwave device have their own unique ids. This field could be used to interpret which IoT Connectivity Module has sent the measurement. This value is same as `id_physical_device` explained in [physical-device endpoint](/api/navigating-data#navigating-physical-devices). The IoT Communication Module has a sticker that matches with `label` attribute in the physical-device endpoint's response.
* **from\_device:** If the event is generated by IoT Connector or your asset, the value is 1. If event is generated by IoT Communicator, the value is 0.
* **event\_type –** Type of the event. Each event has a different event, (i.e. 202 is an event type reporting connectivity changes and 207 is an event type reporting Over The Air update initiation.
* **event\_type\_label:** Label of the data. A brief description of the event occurred. In this example above, the IoT Connector is reporting a boot start event.
* **Occured at –** Timestamp in seconds. This is the exact time of the event occurred.
* **Value:** Value of the event. Some event types have a value to provide more details about the event. The label and description of the event is included in the response with two different attributes. As an example, Event 202 is an event that occurs when IoT Connector is booting. The value is 1, if the device is powered on. The value is 3 if the reboot is due to a configuration change requiring reboot.
* **Datatype:** This will be always null for events
* **event\_value\_label:** Label of the event value. It will be published if the event has a value.
* **event\_value\_description:** Description of the event value when the event has a value.

### Limitations

#### Webhook count:

We currently limit usage to 2 effective webhooks for a given project. We'll be happy to discuss other options if this doesn't accommodate your need.

#### Types of data:

Currently only measurements are pushed. However, sending IoT Connector events is in the roadmap.

### Delivery Guarantee

While the Webhooks have a retry mechanism and will attempt to ensure no data is left unsent. This is a best effort approach.

The webhook mechanism will check the remote server’s HTTP status code. If the returned code is not a “success“ range (2xx) it will add the attempted data to a retry queue and make an attempt at a later time to resend it. Repeat failures are given an escalating back-off timeout, meaning that for every failed attempt to deliver the data, the next attempt is delayed even longer, to prevent the wasting of our server’s time attempting to deliver data to a party that is unreachable.

The resending of failed delivery attempts is done with no guarantee as to the order data is delivered in:

* New incoming data may be delivered before old data is retried.
* Retried data may be resent in a different order than it arrived in, due to the escalating timeout mechanism.

The retry queue is purged on a schedule:

* Messages that had to be retried, but were successful, are purged after 7 days (for record keeping to evaluate reliability).
* Messages that were not delivered are retained for 28 days. After 28 days undelivered data is deleted permanently. This means that if our server is unable to deliver a given data payload to the configured address for the webhook for longer than 28 days, that data is deleted

### Testing The Webhook Functionality

The easiest way to test the webhook functionality is by using the external website like [webhook.site](https://webhook.site). Upon opening this website, it will create a unique instance of a webhook endpoint just for you, which is valid for 24h.

![](/files/RS1yKN2uGDQT4dOP4CoH)

You can share the 'Your Unique URL' in the webhook URL with us to connect any group of devices to it that is currently gathering data. As soon as data is available in IoT Connector, it will be forwarded to the webhook and should be visible on this website.


# Blockbax Integration

[Blockbax ](https://blockbax.com/)is a platform designed to automate business operations through sensor and machine data without the need for coding.

With a few click you can integrate data captured by BACE IoT Platform into Blockbax and create very powerful dashboards to help make sense of your data.

### Steps to follow

1. Creating an inbound Connector in Blockbax Project
2. Creating an access token in Blockbax project
3. Creating a webhook in BACE IoT Platform
4. Creating a new subject type in Blockbax
5. Creating a subject in Blockbax

## Creating an inbound connector in Blockbax Project

In this step you will create an inbound connector to generate a URL endpoint for Webhooks to be sent from BACE IoT Platform.

1. Login to your [Blockbax ](https://login.blockbax.com/)account. Go to Settings -> Inbound Connectors -> (+) Create Inbound connector.&#x20;
2. Provide a name (i.e. BACE Gateway) and under Use template conversion dropdown select **BACE IoT Platform: Measurements webhook** When finished click **Create connector**

<figure><img src="/files/OBkXxujOQHXD7zUOQcEf" alt=""><figcaption></figcaption></figure>

3. Inbound connector is created with a unique endpoint that allows sending data into Blockbax platform. The URL in endpoint field will be used during webhook creating in BACE.

<figure><img src="/files/G6IPv2niiM2uEND94lSw" alt=""><figcaption></figcaption></figure>

## Creating an Access token in Blockbax integration

For integration into Blockbax, you'll also need an access token to send messages to Blockbax endpoint.

1. Go to Settings -> Access Token -> (+) Create access token
2. Give a name to access token (i.e. BACE Integration), and set permission to Measurement writer. Click Create access token

<figure><img src="/files/DfCW3hhK68Augdr16IN5" alt=""><figcaption></figcaption></figure>

3. You will need authorization token for HTTP, so keep **ApiKey \<TOKEN>** in the next step for authorization.

<figure><img src="/files/oIuMW2og52tKo5TC2AJN" alt=""><figcaption></figcaption></figure>

## Creating a Webhook in BACE IoT Platform

In this step, we'll explain how to create a webhook in BACE IoT Platform that will push information to Blockbax inbound connector created in previous step.

1. Login to BACE Panel and click into one of the project that you want to integrate into Blockbax.
2. On left navigation click Integrations -> Webhooks

<figure><img src="/files/o0c9S0nwLGyaXzCiePD6" alt=""><figcaption></figcaption></figure>

3. Click **Create a Webhook** and provide a name to the webhook (i.e. Integration to Blockbax). Make sure to paste URL copied from Blockbax inbound connector into Webhook URL field.
4. Paste the Access token created in previous step inside Authorization field. Paste **ApiKey \<Token>** in this field. DO NOT include Authorization: text.

<figure><img src="/files/ag888aq3j2A6wid3sdEK" alt=""><figcaption></figcaption></figure>

5. When successful you should start seeing Webhook responses inside Blockbax inbound connector&#x20;

<figure><img src="/files/I0ivjsYfPl4K1oVFwtir" alt=""><figcaption></figcaption></figure>

5. &#x20;If you are seeing some messages below loging, the messages are pushed into Blockbax as expected and next step is creating a subject type for these messages.

## Creating a new subject type in Blockbax

For processing data in Blockbax, you need to map incoming data from BACE IoT platform to a Blockbax subject type first. Subject types are like device templates that helps you connecting similar equipment in bulk easily.

1. You need to create Metrics for all data points pushed from BACE IoT Platform. For finding out which datatypes are pushed from BACE, in BACE Panel Go to Modbus Devices -> Click one of the Gateways -> Device Info. As you can see from the example below **Local port, Serial Baud rate, Module Adress** and **DO Power on-state** are being read by BACE.

<figure><img src="/files/Mxw9oRgAOsYZOGMXdvvL" alt=""><figcaption></figcaption></figure>

2. Create a new subject type by clicking Subjects -> Types -> (+) Create a new subject type
3. Provide a name that you can remember. In this example, we are integrating an Ebyte Modbus IO module so we named it with Ebyte IO Module

<figure><img src="/files/3fgGU76jKrM3Wb410FPU" alt=""><figcaption></figcaption></figure>

4. In next screen click **Create Metric** to add all metrics into the subject type.
5. Select ingested, relevant data type and click Create Metric. In this step you can also define additional attributes like unit, upper bound, etc. Refer to Blockbax documentation for each option.

<figure><img src="/files/n0Vj11fpvZGLg4rrCdtF" alt=""><figcaption></figcaption></figure>

6. Add all metrics you want to see in Blockbax dashboard

<figure><img src="/files/IPqTJpBP6k45Ce9cgLfH" alt=""><figcaption></figcaption></figure>

7. When finished with adding all metrics, you can create a subject using the subject template.

## Create a Subject in Blockbax

In next step you need to create a new subject using the subject type that was created in the previous step.

1. Go to Subjects -> Overview -> (+) Create a new subject
2. Select the subject type you have created in previous screen, and provide a name. External ID should match the `source_device` attribute in the BACE Webhook response. This UUID is also available in the BACE Panel URL

<figure><img src="/files/nqbmpY4iHUR8LM06OrzA" alt=""><figcaption><p>UUID of the source_device</p></figcaption></figure>

<figure><img src="/files/slur56ZUCskUUNlEGTXu" alt=""><figcaption><p>Paste UUID in External ID Field</p></figcaption></figure>

3. Click Create Subject to finalize
4. You have successfully integrated data from BACE Platform into Blockbax now! You can continue with creating custom dashboards following steps in [Blockbax documentation](https://blockbax.com/docs/dashboards/).

<figure><img src="/files/zLV5iKH64G5zBNtXxS9Q" alt=""><figcaption></figcaption></figure>


# Wiring IoT Connectivity Modules

Here is a schema to show how to wire up your devices

## BACE Plus

<figure><img src="/files/9GAwn3SJfExBPb709x3I" alt=""><figcaption><p>Wiring for BACE Plus</p></figcaption></figure>

## BACE Plus Zwave / P1

<figure><img src="/files/MnEF7gLf08wMvA35bOr2" alt=""><figcaption><p>Wiring for BACE Plus Zwave / P1</p></figcaption></figure>


# Powering IoT Connectivity Modules

## BACE Plus

1. Connect the power supply provided with the device to an electric outlet.
2. Wait one minute for BACE Plus to boot and start.

<table><thead><tr><th width="150" align="center">LED</th><th width="106.4" align="center">Color</th><th>Mode</th></tr></thead><tbody><tr><td align="center">Power</td><td align="center">🟢</td><td><ul><li>Steady Off: Powered off</li><li>Steady On: Powered on</li></ul></td></tr><tr><td align="center">Modem</td><td align="center">🔵</td><td><ul><li>Steady Off: Not registered to a mobile network</li><li>Blinking: Connected to a mobile network without internet</li><li>Steady On: Connected to a mobile network with internet connection</li></ul></td></tr><tr><td align="center">Cloud</td><td align="center">🟡</td><td><ul><li>Steady off: Disconnected</li><li>Fast Blinking: Gateway storage initializing</li><li>Blinking: Connecting</li><li>Steady on: Connected</li></ul></td></tr></tbody></table>

## BACE Plus with Zwave/P1 add-on board

1. Connect the power supply provided with the device to an electric outlet.
2. Wait one minute for BACE Plus to boot and start.

<table><thead><tr><th width="150" align="center">LED</th><th width="106.4" align="center">Color</th><th>Mode</th></tr></thead><tbody><tr><td align="center">Power</td><td align="center">🟢</td><td><ul><li>Steady off: Powered off</li><li>Steady on: Powered off</li></ul></td></tr><tr><td align="center">Modem</td><td align="center">🔵</td><td><ul><li>Steady Off: Not registered to a mobile network</li><li>Blinking: Connected to a mobile network without internet</li><li>Steady On: Connected to a mobile network with internet connection</li></ul></td></tr><tr><td align="center">Cloud</td><td align="center">🟡</td><td><ul><li>Steady off: Disconnected</li><li>Fast Blinking: Gateway storage initializing</li><li>Blinking: Connecting</li><li>Steady on: Connected</li></ul></td></tr><tr><td align="center">Z-wave</td><td align="center">🟢</td><td><ul><li>Steady off: No paired device</li><li>Blinking: Pairing mode</li><li>Steady on: Paired with a Z-wave node</li></ul></td></tr><tr><td align="center">P1</td><td align="center">🟢</td><td><ul><li>Steady off: No communication with P1 device</li><li>Blink: Malform read error occurred</li><li>Steady On: Communication with P1 device established</li></ul></td></tr><tr><td align="center">Modbus</td><td align="center">🟢</td><td><ul><li>Steady off: No communication with any Modbus device.</li><li>Blink: Communication with at least one Modbus device is established but cannot read/write requested register. Possible Modbus configuration error, please see cloud logs for more details.</li><li>Steady on: Communication with a Modbus device established during last measurement cycle.</li></ul></td></tr></tbody></table>

##


# HTTP Status Codes

When an API request results to an error, BACE sends a response with the error details in the body and a corresponding HTTP status code. The response body contains a description of the error and possible causes.

BACE sends the following HTTP status codes in the header:

* [2xx](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#successful_responses) - The request is successful.
* [4xx](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses) - The request failed because of the information in the request, such as values with incorrect format, or not having the required fields.
* [5xx](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#server_error_responses) - The request failed because of errors with BACE's servers.

### Error Response fields

|         |                                                                                                                                                                                                  |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| name    | A generic description of the problem.                                                                                                                                                            |
| message | An explanation of the error.                                                                                                                                                                     |
| code    | Custom application code for a variation on the given error. For example, this can be a developer-tracked reason for a authentication issue.                                                      |
| status  | The HTTP status code. More information on HTTP Status codes can be found here.                                                                                                                   |
| type    | The type of exception that triggered this error response. Can be interpreted as a developer-readable meaning of the status code, or a custom error class that helps track down potential issues. |

### Example

Here's an example of an error response for a request that uses non existing record id.

```json
{
  "name": "Not Found",
  "message": "The requested record with id 8f14e83c-10a0-46a4-9028-c56916162b7c could not be found or is inaccessible",
  "code": 0,
  "status": 404,
  "type": "yii\\web\\NotFoundHttpException"
}
```

## Troubleshooting requests

### Bad Request - 400

#### Cause <a href="#cause" id="cause"></a>

BACE APIs return this error when:

* The request is malformed or is not in the expected format.

#### Solution

Check the syntax and format of your request.

### Unauthorized - 401

#### Cause <a href="#cause" id="cause"></a>

BACE APIs return this error when:

* You are trying to access API endpoint, but Authorization header is missing in request or API token is not valid.&#x20;
* Your account lacks the permission to access an endpoint.

#### Solution

Make sure that the request is using an existing and valid API token.\
We show all endpoints that you may have access to in the documentation and it is up to your implementation to handle this response gracefully.

If you feel that an endpoint may be of use to you, but you receive an unauthorized response in your application, you may contact us to request additional permissions for your account(s).

Example:

```json
{
    "name": "Unauthorized",
    "message": "Your request was made with invalid credentials.",
    "code": 0,
    "status": 401,
    "type": "yii\\web\\UnauthorizedHttpException"
}
```

### Not Found - 404

#### Cause <a href="#cause" id="cause"></a>

BACE APIs return this error when:

* A request is trying to perform an operation on a resource that does not exist.
* A POST request contains a resource ID that does not exist.

#### Solution

Make sure that the request is using an existing resource ID. Make sure you are using correct route, and you do not have typo in your URL.


# Connecting BACE to Default WiFi

BACE devices with WiFi capability have by default a WiFi network configured, this can be used in case the device does not have any other options to connect to the internet, e.g. cellular connection is impossible and Ethernet is not available.

Default SSID or Hotspot name: `-`

Default (Hotspot) Password: `Pd&51uJZZ$o*ZG&F`

{% hint style="info" %}
Default WiFi settings will only work is WiFi settings has not been modified to connect to an other network
{% endhint %}

The easiest option to set up a access point for the device to connect to is to enable a Hotspot on a phone, an example here on a Android phone, can be found under Settings.

<figure><img src="/files/gYlhqXgPDkTh2Br8aPTY" alt=""><figcaption><p>How to setup Hotspot in Android</p></figcaption></figure>

Similar steps could be followed for setting up Hotspot for iOS devices. Here are a few handy links to do that.

1. [How to change SSID in iOS](https://www.techcoil.com/blog/how-to-change-your-wifi-ssid-or-wifi-name-of-your-iphone-hotspot/)
2. [How to setup Hotspot in iOS](https://support.apple.com/en-us/HT204023)

You could also setup this access point on a router, when you do, make sure you have DHCP enabled and the router has internet, so the device gets an IP address and can connects to our servers.


