ZeroKey Spatial Intelligence Platform API (3.0.4)

Download OpenAPI specification:Download

Introduction

The ZeroKey Spatial Intelligence Platform (ZSIP) API is the main manner in which modules, applications, and tools interact with ZeroKey's Spatial Intelligence Platform. Through this API core functions of the underlying Quantum RTLS hardware are accessible, providing direct control of devices and system operation.

The Spatial Intelligence Platform relies on a SignalR based Event Hub system to relay real-time information from the Quantum RTLS hardware to ZSIP and then to connected modules and applications. End-users may establish a direct read-only SignalR connection to the Event Hub by requesting a connection ID through this API. Each connection to the Event Hub must specify a filter chain, which ultimately determines which messages transmitting through the Event Hub will be relayed to the client. Several pre-defined templates are available to handle a number of common use-cases.

Architecture Diagram

What's New

Features

  • The Quality of Service (QoS) feature is a new addition to API that allows users to set the message rate per second and batch messages. This feature is for use cases where every position output from the system is not required. It is used to lower the rate of positioning messages for client consumption. This will not affect internal system latency or message rates.
    • When enabling the rate limit with no batching, the system will output LOCATION_FILTER_UPDATE per device. It will collect the latest position for each device, then at the interval for the rate specified, will produce a LOCATION_FILTER_UPDATE with the devices last known position.
    • When batching is selected, the system will collect all LOCATION_RAW_UPDATES for all devices, then at the specified rate interval will output one LOCATION_BATCH_UPDATE containing a list of LOCATION_RAW_UPDATE messages.
  • The MQTT TLS is now available. This feature allows users to encrypt the whole MQTT communication by using TLS instead of plain TCP. This feature provides a secure and trusted communication channel between MQTT clients and brokers
  • Certificate profile management is another feature that allows users to manage their certificates more efficiently. This feature enables users to create, update, and delete certificates easily. It also allows users to manage their certificate authority (CA), client certificate, client key under a certificate profile.

Breaking Changes

  • LOCATION_UPDATE is deprecated. It is replaced with LOCATION_RAW_UPDATE
  • BATCH_LOCATION_UPDATE is deprecated. It is replaced with LOCATION_BATCH_UPDATE

Get Started

ASP.NET SignalR is a library for ASP.NET developers that simplifies the process of adding real-time web functionality to applications. This option offers the best solution for capturing and processing data as it happens. It enables you to access the most current and accurate information from our devices. This option can be beneficial for applications that need quick and reliable feedback, such as monitoring, analytics, or decision making.

Authentication Process

Two authentication paradigms are available, OAuth2 (Client Credentials) and API keys. The OAuth method allows the greatest flexibility and security in allowing end-client applications to make API calls directly to the platform.

Three access paradigms are supported, with the first option being the preferred authentication flow:

  1. End-user clients authenticate with the third-party backend. The backend service related to that application uses its API key or admin-level Client Credentials to obtain an OAuth token. This token may be relayed back to the end-client application, who can begin making API calls directly using the token.
  2. Another approach is to simply make all API requests through the third-party backend entirely and pass no auth tokens to the end-client.
  3. The last option is to create duplicate user accounts within the third-party application and ZSIP. The end-client application can then interact directly with the API and obtain its own auth_token using its Client Credentials.

The following sequence diagram illustrates the recommended approach (option 1):

Authentication Sequence Diagram

OAuth2

This API uses OAuth 2 authentication flows with the client_credentials grant_type for accessing all operations. See the Authentication section for more detailed process information.

Security Scheme Type: OAuth2
Flow type: clientCredentials
Token URL: /auth/token
Scopes:
  • observer -

    Grants read-only observer access (currently not available)

  • user -

    Grants user-level access (currently not available)

  • admin -

    Grants admin-level access

ApiKey

An API key provides admin scope access to the system and is intended to be used by back-end services only.

Security Scheme Type: API Key
Header parameter name: X-API-KEY

Prerequisite

  • Install SignalR client library in languages supported. SignalR supports most of the popular languages. Make sure the language you use has a signalR client library available.
  • Have a calibrated ZK system running. Refer to the User Guides that are included in ZeroKey SDK at your installed directory for details.
  • Connect the Gateway from the above system to the ECD.

You need to find the Event Hub/API hosting IP address before starting the coding steps. There are two ways to do so:

  • (AP Mode) Connect your machine to the ECD's WiFi. The default SSID is QuantumRTLS and the password is zerokeypilotkit. The hosting IP address by default is 10.42.0.1
  • (Ethernet) Connect the ECD to your Ethernet. Plugin a monitor to the ECD and you will see the hosting IP show up.

.NET (C#)

To establish a connection to the SignalR Event Hub endpoint, it is first required to obtain an EndpointID by using the Connection Management API operation. After the new Event Hub connection request has been created, we are ready to connect to the Event Hub. Follow these steps to create a project that can connect to the Event Hub:

  1. Create a Blazor app in your Visual Studio
  2. Install the following NuGet packages from the NuGet package manager: SignalR.Client Newtonsoft.Json
  3. Create a new .razor file under "Pages" folder and name it "ConnectionTest.razor"
  4. Copy and paste the following code sample to the file
  5. Replace {API Host Here} with your actual hosting address. For example, 127.0.0.1 . Replace {YOUR USERNAME}} and {YOUR PASSWORD} with your own credential info.
@using System.Text;
@using Microsoft.AspNetCore.SignalR.Client;
@using Newtonsoft.Json;

@page "/connectionTest"

<PageTitle>Connection Test</PageTitle>

<h1>Connection Test</h1>

@foreach (var item in m_receivedData)
{
   <p>@item</p>
}


@code {
   List<string> m_receivedData = new List<string>();
   //Declaring some C# classes to store the results
   private class AuthResponseData
   {
       public string access_token { get; set; }
       public string token_type { get; set; }
       public int expires_in { get; set; }
       public string scope { get; set; }
       public AuthResponseUserData User { get; set; }
   }
   private class AuthResponseUserData
   {
       public string auth_id { get; set; }
       public string AccessLevel { get; set; }
   }

   private class ApiKeyData
   {
       public string ApiKey { get; set; }
   }
   private class ConnectionData
   {
       public string EndpointURI { get; set; }
       public string EndpointID { get; set; }
       public HubInfo HubInfo { get; set; }
   }

   private class HubInfo
   {
       public string HubName { get; set; }
       public string HubTypeID { get; set; }
       public string HubInstanceID { get; set; }
   }

   protected override async Task OnInitializedAsync()
   {
       await StartConnectionAsync();
   }

   public async Task StartConnectionAsync()
   {
       var httpClient = new HttpClient();

       var authDataJson = "{\"grant_type\":\"client_credentials\",\"auth_id\":\"{YOUR USERNAME}\",\"auth_secret\":\"{YOUR PASSWORD}\"}";

       // Request OAuth token
       var oauthTokenResponse = await httpClient.PostAsync("http://{API Host Here}:5000/v3/auth/token", new StringContent(authDataJson, Encoding.UTF8, "application/json"));
       var oauthTokenJson = await oauthTokenResponse.Content.ReadAsStringAsync();
       var oauthToken = JsonConvert.DeserializeObject<AuthResponseData>(oauthTokenJson);

       // Register API Key
       httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {oauthToken.access_token}");
       var apiKeyResponse = await httpClient.PostAsync("http://{API Host Here}:5000/v3/auth/registerApiKey", new StringContent(string.Empty));
       var apiKeyJson = await apiKeyResponse.Content.ReadAsStringAsync();
       var apiKey = JsonConvert.DeserializeObject<ApiKeyData>(apiKeyJson);
       httpClient.DefaultRequestHeaders.Remove("Authorization");

       //Default filter to only receive position events
       var filterJson = "{\"Filters\":[{\"FilterTemplate\":\"position_events\"}]}";

       //Request connection info
       httpClient.DefaultRequestHeaders.Add("X-API-KEY", apiKey.ApiKey);
       var connectionInfoResponse = await httpClient.PostAsync("http://{API Host Here}:5000/v3/events/connections", new StringContent(filterJson, Encoding.UTF8, "application/json"));
       var connectionInfoJson = await connectionInfoResponse.Content.ReadAsStringAsync();
       var connectionInfo = JsonConvert.DeserializeObject<ConnectionData>(connectionInfoJson);

       //Build connection and handling of events
       var eventHubConnection = new HubConnectionBuilder().WithUrl("http://{API Host Here}:33001/hubs/eventHub",    //EndpointURI obtained from last step
           (opts) =>
           {
               opts.AccessTokenProvider = () => Task.FromResult(connectionInfo.EndpointID);    //EndpointID obtained from last step
           }).Build();

       var eventHubMessageSubscription = eventHubConnection.On<string>("Event", async (message) =>
       {
           //Handle the event here
           m_receivedData.Add(message);
           await InvokeAsync(StateHasChanged);
       });

       //Start the connection
       await eventHubConnection.StartAsync();
   }
}
  1. In your Shared/NavMenu.razor file, insert the following code:
<div class="nav-item px-3">
   <NavLink class="nav-link" href="connectionTest">
       <span class="oi oi-list-rich" aria-hidden="true"></span> Connection Test
   </NavLink>
</div> 
  1. Open the dropdown right beside launch project button. Select your_project_name Debug Properties. In App URL section, change the address from https to http
  2. Run your app through Visual Studio

JavaScript

To establish a connection to the SignalR Event Hub Endpoint, it is first required to obtain an EndpointID by using the Connection Management API operation. After the new Event Hub connection request has been created, we're ready to connect to the Event Hub. Follow these steps to create a project that can connect to the Event Hub:

  1. Create an .html file containing the following code:
  2. Replace {API Host Here} with your actual hosting address. For example, 127.0.0.1 . Replace {YOUR USERNAME}} and {YOUR PASSWORD} with your own credential info.
  3. Open the file in your web browser
<script src="https://code.jquery.com/jquery-3.6.3.js" integrity="sha256-nQLuAZGRRcILA+6dMBOvcRh5Pe310sBpanc6+QBmyVM="
   crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>

<body>
   <div id="container">

   </div>
</body>

<script>
   const eventHubUrl = "http://{API Host Here}:33001/hubs/eventHub"; // url of event hub signalR
   const apiUrl = "http://{API Host Here}:5000/v3/"; // url of the EventHub API

   $(document).ready(async function () {
       var endpointID = await getEndpointID();
       
       const connection = new signalR.HubConnectionBuilder()
           .withUrl(eventHubUrl,
               {
                   accessTokenFactory: () => {
                       return endpointID;
                   }
               })
           .configureLogging(signalR.LogLevel.Information)
           .build();

       connection.on("Event", data => {
           // TODO: do something with data
           var node = document.getElementById("container");
           var newNode = document.createElement("p");
           newNode.appendChild(document.createTextNode(data));
           node.appendChild(newNode);
       });

       connection.onclose(async () => {
           //TODO: do something for close event
       });

       await connection.start();
   });

   async function getEndpointID() {
       var accessToken;
       var endpointID;
       try {
           // Get the Bearer Token
           await fetch(
               apiUrl + "auth/token",
               {
                   method: "POST",
                   headers: {
                       "Content-Type": "application/json"
                   },
                   body: JSON.stringify({
                       grant_type: "client_credentials",
                       auth_id: "{YOUR USERNAME}",
                       auth_secret: "{YOUR PASSWORD}"
                   })
               })
               .then(response => response.json())
               .then(result => {
                   accessToken = result["access_token"];
               })
               .catch(error => {
               });

           // Initiate connection details
           await fetch(
               apiUrl + "events/connections",
               {
                   method: "POST",
                   headers: {
                       "Content-Type": "application/json",
                       "Authorization": `Bearer ${accessToken}`
                   },
                   body: JSON.stringify({
                       "Mode": "read",
                       "Filters": [{ "FilterTemplate": "position_events" }]
                   })
               })
               .then(response => response.json())
               .then(result => {
                   endpointID = result["EndpointID"];
               })
               .catch(error => {

               });
       } catch (e) {
           console.log(e);
       }

       return endpointID;
   }
</script> 

Python

To establish a connection to the SignalR Event Hub endpoint, it is first required to obtain an EndpointID by using the Connection Management API operation. After the new Event Hub connection request has been created, we're ready to connect to the Event Hub. Follow these steps to create a project that can connect to the Event Hub:

  1. Install required libraries through pip in your terminal:
pip install signalrcore 
  1. Create a .py file containing the following code:
import requests
import json
from signalrcore.hub_connection_builder import HubConnectionBuilder

eventHubUrl = "http://{API Host Here}:33001/hubs/eventHub" # Url of event hub signalR
apiUrl = "http://{API Host Here}:5000/v3/"  # Url of the EventHub API

def main():
   hub_connection = HubConnectionBuilder()\
       .with_url(eventHubUrl,
                 options={
                     "access_token_factory": authenticateConnection
                 })\
       .build()

   hub_connection.on_open(lambda: print(
       "connection opened and handshake received ready to send messages"))
   hub_connection.on_close(lambda: print("connection closed"))
   hub_connection.on("Event", print)
   hub_connection.start()


def authenticateConnection():
   # Get Bearer token
   headers = {
       "Content-Type": "application/json"
   }
   body = json.dumps({
       "grant_type": "client_credentials",
       "auth_id": "{YOUR USERNAME}",
       "auth_secret": "{YOUR PASSWORD}"
   })
   authTokenResponse = requests.post(
       apiUrl + "auth/token", headers=headers, data=body)
   authToken = authTokenResponse.json()["access_token"]

   # Initiate connection details to obtain EndpointID
   headers = {
       "Content-Type": "application/json",
       "Authorization": "Bearer " + authToken
   }
   body = json.dumps({
       "QualityOfService": {
           "MaxUpdateRate": 20,
           "MaxThroughput": 10240,
           "AutotuneConnectionParameters": False
       },
       "Mode": "read",
       "Filters": [{"FilterTemplate": "position_events"}]
   })
   endpointIDResponse = requests.post(
       apiUrl + "events/connections", headers=headers, data=body)
   endpointID = endpointIDResponse.json()["EndpointID"]

   return endpointID

if __name__ == "__main__":
   main()
  1. Replace {API Host Here} with your actual hosting address. For example, 127.0.0.1 . Replace {YOUR USERNAME}} and {YOUR PASSWORD} with your own credential info.
  2. Run the .py file created by the terminal command:
python -i ./FILE_NAME_CREATED.py 

JAVA

To establish a connection to the SignalR Event Hub endpoint, it is first required to obtain an EndpointID by using the Connection Management API operation. After the new Event Hub connection request has been created, we're ready to connect to the Event Hub. Follow these steps to create a project that can connect to the Event Hub:

  1. Create a JAVA project. This example is using Gradle.
  2. In build.gradle file, insert the following dependency under the dependencies section:
implementation 'org.slf4j:slf4j-jdk14:1.7.25'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'org.apache.commons:commons-text:1.6'
implementation 'org.json:json:20231013' 
  1. Create a new file called SampleClass.java in the same directory of the App.java. And copy paste the code below:
package javadoc;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.microsoft.signalr.HubConnection;
import com.microsoft.signalr.HubConnectionBuilder;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Single;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class SampleClass {
    private String eventHubUrl = "http://{API Host Here}/hubs/eventHub";
    private String apiUrl = "http://{API Host Here}:5000/v3";
    private String username = "{YOUR USERNAME}";
    private String password = "{YOUR PASSWORD}";

    public void init() throws Exception {
        String token = getToken();
        String eventHubApiKey = registerApikey(token);
        HubConnection hubConnection = GetEventHubConnection(eventHubApiKey);

        hubConnection.on("Event", (event) -> {
            System.out.println(event);
        }, String.class);

        hubConnection.start();
    }

    public String getToken() throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("grant_type", "client_credentials");
        jsonObject.put("auth_id", username);
        jsonObject.put("auth_secret", password);

        OkHttpClient client = new OkHttpClient.Builder().build();
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");

        Request request = new Request.Builder()
                .url(apiUrl + "/auth/token")
                .post(RequestBody.create(mediaType, jsonObject.toString()))
                .build();

        final String[] result = { null };
        CountDownLatch latch = new CountDownLatch(1);
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {

                latch.countDown();
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                JSONObject j_response;
                String responseString = "";
                try {
                    responseString = response.body().string();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (!response.isSuccessful()) {
                    latch.countDown();
                    return;
                } else {
                    try {
                        j_response = new JSONObject(responseString);
                        result[0] = j_response.getString("access_token");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                latch.countDown();
            }
        });

        latch.await();

        return result[0];
    }

    public String registerApikey(String apiToken) throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("grant_type", "client_credentials");
        jsonObject.put("auth_id", username);
        jsonObject.put("auth_secret", password);

        OkHttpClient client = new OkHttpClient.Builder().build();
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");

        Request request = new Request.Builder()
                .url(apiUrl + "/auth/registerApiKey")
                .addHeader("Authorization", "Bearer " + apiToken)
                .post(RequestBody.create(mediaType, jsonObject.toString()))
                .build();

        final String[] result = { null };
        CountDownLatch latch = new CountDownLatch(1);
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                latch.countDown();
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                JSONObject j_response;
                String responseString = "";
                try {
                    responseString = response.body().string();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                if (!response.isSuccessful()) {
                    latch.countDown();
                    return;
                } else {
                    try {
                        j_response = new JSONObject(responseString);
                        result[0] = j_response.getString("ApiKey");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                latch.countDown();
            }
        });

        latch.await();

        return result[0];
    }

    public HubConnection GetEventHubConnection(String eventHubApiKey) throws Exception {

        String connectionId = GetConnectionID(eventHubApiKey);

        HubConnection hubConnection = HubConnectionBuilder.create(eventHubUrl)
                .withAccessTokenProvider(Single.defer(() -> {
                    return Single.just(connectionId);
                })).build();
        return hubConnection;
    }

    public String GetConnectionID(String eventHubApiKey) throws Exception {
        JSONObject jsonObject = new JSONObject();
        JSONArray filters = new JSONArray();
        JSONObject filter = new JSONObject();

        filter.put("FilterTemplate", "position_events");
        filters.put(filter);

        jsonObject.put("Filters", filters);

        OkHttpClient client = new OkHttpClient.Builder().build();
        MediaType mediaType = MediaType.parse("application/json;");

        Request request = new Request.Builder()
                .url(apiUrl + "/events/connections")
                .post(RequestBody.create(mediaType, jsonObject.toString()))
                .addHeader("X-API-KEY", eventHubApiKey)
                .addHeader("Content-Type", "application/json")
                .build();

        final String[] result = { null };
        CountDownLatch latch = new CountDownLatch(1);

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                latch.countDown();
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (response.isSuccessful()) {
                    try {
                        JSONObject j_response = new JSONObject(response.body().string());
                        result[0] = j_response.getString("EndpointID");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                latch.countDown();
            }
        });

        latch.await();

        return result[0];
    }

}
  1. Insert the following code to main method of your App.java:
        SampleClass sample = new SampleClass();
        String token = sample.getToken();
        String eventHubApiKey = sample.registerApikey(token);
        HubConnection hubConnection = sample.GetEventHubConnection(eventHubApiKey);

        hubConnection.on("Event", (event) -> {
            System.out.println(event);
        }, String.class);

        hubConnection.start();
  1. Replace {API Host Here} with your actual hosting address. For example, 127.0.0.1 . Replace {YOUR USERNAME}} and {YOUR PASSWORD} with your own credential info.
  2. Build and run the project.

Event Hub

Within the Spatial Intelligence Platform, data is primarily routed between various logical components of the platform through a specialized Event Hub backed by .NET Core's SignalR protocol. SignalR is a highly efficient and scalable protocol for distribution of real-time data. The ZSIP implementation of SignalR as an Event Hub extends the standard functionality with the concept of a per-connection FilterChain, which matches against messages traversing the hub to select and relay only the relevant messages for a particular connection. This architecture enables a highly efficient communication backbone capable of exchanging high volume, low latency data, without saturating all client links with miscellaneous data unrelated to their particular function.

Authentication

To establish a connection to the SignalR Event Hub endpoint, it is first required to obtain an EndpointID by using the Connection Management API operation. The EndpointID from the response must be presented as a Bearer token within the Authorization header of the SignalR connection request.

$(document).ready(function(){
    const oauth_token = "{TOKEN HERE}";
    
    const ZSIP_API = "https://{API Host Here}/v3/";
    const NewConnection_OperationID = "events/connections";
    
    $.ajax({
        url: ZSIP_API + NewConnection_OperationID,
        type: 'POST',
        beforeSend: function (xhr) {
            xhr.setRequestHeader('Authorization', 'Bearer ' + oauth_token);
        },
        contentType: 'application/json',
        data: JSON.stringify({
            Mode: 'read',
            Filters: [
                {
                    FilterTemplate: "dashboard"
                }
            ]
        }),
        success: function(data) {
            connectToEventHub(data.EndpointURI, data.EndpointID);
        },
        error: function() {
            console.log("API request failure");
        }
    });
});

Response success

Response Schema: application/json
EndpointURI
string

Endpoint URI for the SignalR EventHub connection.

EndpointID
string

The unique ID of the connection, this must be passed in the Authorization header as a bearer token when establishing the SignalR connection.

object
application/json
{
  • "EndpointID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
  • "HubInfo": {
    }
}

Establishing a Connection

After the new Event Hub connection request has been created, we are ready to connect to the Event Hub.

function connectToEventHub(endpoint, id)
{
    var connection = new signalR.HubConnectionBuilder()
    .withUrl(endpoint,
    {
        accessTokenFactory: () => {
            return id;
        }
    })
    .build();
    
    connection.on("Event", function (message) {
        console.log(message);
    });

    connection.start().then(function () {
        console.log("Connected to Event Hub!");
    }).catch(function (err) {
        return console.error(err.toString());
    });
}

Advanced Connection Options

Several Quality of Service options are available to assist with managing low-bandwidth and/or high-latency links. The MaxUpdateRate indicates the maximum number of packets per second sent to a client. The Event Hub uses a sliding window algorithm to determine if this threshold has been exceeded, and once it has, it begins to batch messages together to avoid exceeding the limit. The MaxThroughput property monitors the total bandwidth (not including protocol overhead) and if exceeded, a notice message is forwarded to the client and excess data is truncated. An experimental auto-tune feature is enabled by setting the AutotuneConnectionParameters property to true. When this feature is enabled, the Event Hub will attempt to adjust the parameters in real-time to achieve the best available performance.

Array of objects (FilterChain)

All filters in this array are compared with a logical OR operation, while all filters listed as children objects within each filter are compared with a logical 'AND'.

{
  • "Filters": [
    ]
}

Methods

Once a connection is established, the client must handle a basic RPC method to receive messages from the server.

Method Arguments Description
Event <JSON Object> Primary RPC for receiving messages from the Event Hub

Event Schema

Messages routed through the Event Hub are serialized JSON objects and follow this schema definition, with event specific data being contained as a JSON object within the Content property.

Event Hub object schema

ModuleID
string

ID of the module that generated the message.

object
Category
string

Category of the Event, common categories are:

Category Description
POSITION Messages containing position updates from the devices
GATEWAY Raw messages received from the gateway devices
ZONE Zone alerts from the Zone module
HARDWARE Hardware events, such as button presses, battery level updates, and other actionable events
SYSTEM System-level events, e.g. admin shutdown
API API operation that has been relayed over the Event Hub
Type
string

Sub-category that further identifies the purpose of the event and is specific to each category.

Timestamp
string

An ISO 8601 style timestamp with 1ms precision of the format YYYY-MM-DDThh:mm:ss.ssssZ

object

Event-specific JSON object data.

{
  • "ModuleID": "cae534a0-cb29-4d22-a16c-70f764aedbcb",
  • "Source": {
    },
  • "Category": "HARDWARE",
  • "Type": "BATTERY_LEVEL",
  • "Timestamp": "",
  • "Content": {
    }
}

Event Categories

Events are classified into a Category and Type, the latter indicating a sub-category specific to the particular Category. Event messages adhere to a common outer-schema with a event-specific Content property. Minimal validation of message content is done aside from schema validation, allowing for flexible and complex functionality between an expansive list of modules, integrations, and end-user solutions. As an example, just because a message may have the Category of POSITION, it is not always the case that this message originated from the Quantum RTLS hardware and may have originated from a simulator module.

POSITION

Type Description
LOCATION_RAW_UPDATE A position update from a mobile device containing the last known X,Y,Z coordinates in metres and the orientation as a quaternion
object
{
  • "Content": {
    }
}
Type Description
LOCATION_FILTER_UPDATE A position update from a mobile device containing the last known X,Y,Z coordinates in metres and the orientation as a quaternion.
object
{
  • "Content": {
    }
}
Type Description
LOCATION_BATCH_UPDATE A batched position update from multiple mobile devices containing the last known X,Y,Z coordinates in metres and the orientation as a quaternion
Array
object
[
  • {
    }
]

GATEWAY

Type Description
RAW_MESSAGE Raw messages received as output directly to the Gateway Module
object
{
  • "Content": {
    }
}

ZONE

Type Description
ZONE_ENTRY Indicates a device has entered a Zone
object
{
  • "Content": {
    }
}
Type Description
ZONE_EXIT Indicates a device has exited a Zone
object
{
  • "Content": {
    }
}
Type Description
ZONE_NOTIFY Notifies a state change has occured to the following zone with its update definition
object
{
  • "Content": {
    }
}

HARDWARE

Type Description
BATTERY_LEVEL A period update about a device's battery level
object
{
  • "Content": {
    }
}
Type Description
BUTTON_PRESS A message indicating one of a device's buttons was pressed
object
{
  • "Content": {
    }
}
Type Description
ALERT_STATE Indicates a change in alert state of a device
object
{
  • "Content": {
    }
}
Type Description
DEVICE_STATE Indicates a change in device state
object
{
  • "Content": {
    }
}

SYSTEM

Type Description
RESTART Action task to restart the Quantum RTLS system
SHUTDOWN Action task to stop the Quantum RTLS system
START Action task to start the Quantum RTLS system
Type Description
ERROR Critical system error message
WARNING System-level warning
object
{
  • "Content": {
    }
}

API

Type Description
REQUEST An API request encapsulated in an event
RESPONSE An API response encapsulated in an event

DATA EXPORT

Type Description
REQUEST_COMPLETED Indicates that a requested export task has been completed

Authentication

API operations related to authentication operations, see the Authentication Process section for a detailed description of the authentication flows available.

Get an OAuth2 token

Request
Request Body schema: application/json

Get an OAuth2 token

grant_type
string

Only the Client Credentials grant type is currently supported.

Value: "client_credentials"
auth_id
string
auth_secret
string
Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/auth/token
Request samples
application/json
{
  • "grant_type": "client_credentials",
  • "auth_id": "admin",
  • "auth_secret": "password"
}
Response samples
application/json
{
  • "access_token": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
  • "token_type": "bearer",
  • "expires_in": 3600,
  • "scope": "observer",
  • "User": {
    }
}

Obtain a new API Key

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

post/auth/registerApiKey
Request samples
Response samples
application/json
{
  • "ApiKey": "string"
}

Revoke an API key

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Revoke an API key

ApiKey
string
Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/auth/revokeApiKey
Request samples
application/json
{
  • "ApiKey": "string"
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

System Settings

Global system settings relating to the core functions of the platform. These are usually configured at the time of initial system setup.

Get the current system state and settings

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/system
Request samples
Response samples
application/json
{
  • "settings": {
    },
  • "devices": [
    ],
  • "modules": [
    ],
  • "zones": [
    ]
}

Quality of Service

Global quality of service of the platform.

Get the current quality of service settings

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/system/rateLimit
Request samples
Response samples
application/json
{
  • "Rate": 1,
  • "Batch": false
}

Set quality of service

SecurityOAuth2 or ApiKey
Request
Request Body schema: applicajon/json

Set quality of service

Rate
number

The number of messages received per second.

Batch
boolean
Default: false

Indicate batching of messages option.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/system/rateLimit
Request samples
applicajon/json
{
  • "Rate": 1,
  • "Batch": false
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

User Management

Global system user management.

Get all current users info

SecurityOAuth2 or ApiKey
Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

get/system/users
Request samples
Response samples
application/json
[
  • {
    }
]

Add a new users

SecurityOAuth2 or ApiKey
Request
Request Body schema: applicajon/json

Set quality of service

FullName
string

The full name of the user

Username
string

The username of the user

Authority
string

The access level granted to the user

Enum: "observer" "user" "admin"
Password
string

The current password of the user

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/system/user
Request samples
applicajon/json
{
  • "FullName": "Zero Key",
  • "Username": "Zerokey",
  • "Authority": "observer",
  • "Password": "string"
}
Response samples
application/json
[
  • {
    }
]

Update info of target user

SecurityOAuth2 or ApiKey
Request
path Parameters
UserID
required
string

The UserID of the target user

Request Body schema: applicajon/json

Set updated info of the target user

FullName
string

The full name of the user

Username
string

The username of the user

Authority
string

The access level granted to the user

Enum: "observer" "user" "admin"
Password
string

The current password of the user

NewPassword
string

The new password of the user

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

put/system/user/{UserID}
Request samples
applicajon/json
{
  • "FullName": "Zero Key",
  • "Username": "Zerokey",
  • "Authority": "observer",
  • "Password": "string",
  • "NewPassword": "string"
}
Response samples
application/json
{
  • "UserID": "1800ac5a-f146-45f3-aedc-d62845570b86",
  • "FullName": "Zero Key",
  • "Username": "Zerokey",
  • "Authority": "observer",
  • "CreatedTimestamp": "2016-05-16T00:00:00.0000Z",
  • "ModifiedTimestamp": "2016-05-16T00:00:00.0000Z"
}

Delete target user

SecurityOAuth2 or ApiKey
Request
path Parameters
UserID
required
string

The UserID of the target user

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

delete/system/user/{UserID}
Request samples
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Connection Management

Initiate a new SignalR connection to the event hub

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Initiate a new SignalR connection to the event hub

Array of objects (FilterChain)

All filters in this array are compared with a logical OR operation, while all filters listed as children objects within each filter are compared with a logical 'AND'.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/events/connections
Request samples
application/json
{
  • "Filters": [
    ]
}
Response samples
application/json
{
  • "EndpointID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
  • "HubInfo": {
    }
}

Update the message filter associated with the specified EndpointID

SecurityOAuth2 or ApiKey
Request
path Parameters
EndpointID
required
string

ID of the endpoint

Request Body schema: application/json

Update connection properties of a SignalR connection

Array of objects (FilterChain)

All filters in this array are compared with a logical OR operation, while all filters listed as children objects within each filter are compared with a logical 'AND'.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

put/events/connections/{EndpointID}
Request samples
application/json
{
  • "Filters": [
    ]
}
Response samples
application/json
{
  • "EndpointID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
  • "HubInfo": {
    }
}

Event Debugging

Admin-level operations to interact, debug, and test lower-level logic of modules.

Inject a message to the event hub

SecurityOAuth2 or ApiKey
Request
Request Body schema: applicajon/json

Post a message to the event hub

object (Event)

Event Hub object schema

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/events
Request samples
applicajon/json
{
  • "EventData": {
    }
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Device Information

Operations in the Device Information group will provide the last known properties of a given device, even if that device is not currently connected to the network.

Get information about all devices present on the system

Warning: Do not use this for time sensitive retrieval.

The device information is currently snapshotted on an interval

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/devices
Request samples
Response samples
application/json
[
  • {
    }
]

Get detailed information about a specific device

Warning: Do not use this for time sensitive retrieval.

The device information is currently snapshotted on an interval

SecurityOAuth2 or ApiKey
Request
path Parameters
address
required
string

Address of the device (usually it's MAC address)

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

404

Resource was not found.

get/devices/{address}
Request samples
Response samples
application/json
{
  • "DeviceID": "00:AA:BB:CC:DD:EE",
  • "Position": [
    ],
  • "Orientation": [
    ],
  • "DeviceFlags": 3,
  • "AlertState": "active",
  • "FirmwareHash": "ec95199c",
  • "FirmwareVersion": "0.10.0",
  • "DeviceType": "anchor",
  • "LastUpdateTime": "2019-08-24T14:15:22Z",
  • "BatteryLevel": 0.85,
  • "LastGatewaySource": "ZK://501::3F2504E0-4F89-11D3-9A0C-0305E82C3301::UDP::10.0.0.220:10000"
}

Device Control

The device control operations provide a hardware abstraction layer to enable directly addressing and controlling end-devices, without regard to their specific model or type.

Update device settings

SecurityOAuth2 or ApiKey
Request
path Parameters
address
required
string

Address of the device (usually it's MAC address)

Request Body schema: application/json

Update device settings.

AlertState
string

The alert state of a device indicates whether it is currently alarming by flashing it's alarm LED, and exciting its buzzer and vibration motor.

Enum: "off" "active"
Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/devices/{address}
Request samples
application/json
{
  • "AlertState": "active"
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Set the alert state of the device

SecurityOAuth2 or ApiKey
Request
path Parameters
address
required
string

Address of the device (usually it's MAC address)

Request Body schema: application/json

Set the alert state of a device

AlertState
string

The alert state of a device indicates whether it is currently alarming by flashing it's alarm LED, and exciting its buzzer and vibration motor.

Enum: "off" "active"
Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/devices/{address}/alertState
Request samples
application/json
{
  • "AlertState": "active"
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Module Management

The module interface allows hot-plugging of add-on functionality as may be needed for a given use-case. These API operations provide administrative functions for installing, licensing, and configuring modules.

Get version number info of the EventHub

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/version
Request samples
Response samples
application/json
{
  • "EventHubVersion": "0.2.4"
}

Get details of currently defined modules

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/modules
Request samples
Response samples
application/json
[
  • {
    }
]

Historian

The Historian module provides logging and log exporting functionality for both positional and collision data.

Requests position updates events based on the requested filter conditions

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Requests position updates events based on the requested filter conditions

Array
StartTime
string <date-time>

The minimum date and time range used to filter positional data.

EndTime
string <date-time>

The maximum date and time range used to filter positional data.

DeviceID
string

A 6-byte MAC address associated to the device. This is usually the MAC address associated with the radio or Ethernet interface, depending on the particular device.

Responses
201

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/modules/historian/positionUpdates
Request samples
application/json
[
  • {
    }
]
Response samples
application/json
{
  • "TaskID": "string"
}

Requests zone collisions events

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Requests zone collisions events based on the requested filter conditions

ZoneIDs
Array of strings

The list of zones to retrieve collision data for

Array of objects (DeviceFilter)

Specifies the list of device based filters that are involved in an collision

IncludePositionalData
boolean
Default: false

Indicates whether the filtered result should include the interleaved positional data, or not

Responses
201

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/modules/historian/zoneCollisions
Request samples
application/json
{
  • "ZoneIDs": [
    ],
  • "Devices": [
    ],
  • "IncludePositionalData": false
}
Response samples
application/json
{
  • "TaskID": "string"
}

Retrieve the export file content

SecurityOAuth2 or ApiKey
Request
path Parameters
TaskID
required
string

ID from the previous export request

Example: b3ef466f-0486-469b-a9e1-04740a814af6
Responses
200

Response success.

401

Unauthorized access, invalid credentials were used.

404

Resource was not found.

get/modules/historian/file/{TaskID}
Request samples
Response samples
application/json
{
  • "AttachedFile": "string"
}

MQTT

Get MQTT module settings and active connections.

SecurityOAuth2 or ApiKey
Responses
200

Response success.

401

Unauthorized access, invalid credentials were used.

404

Resource was not found.

get/modules/mqtt
Request samples
Response samples
application/json
[
  • {
    }
]

Establish a new MQTT connection

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Establish a new MQTT connection

host
string

IP or hostname of the MQTT broker.

port
integer
Default: 8883

Port of the MQTT service. (IANA registered ports (1883 unencrypted, 8883 TLS)

TLS
boolean
Default: true

Indicate if connection is using TLS

CertificateProfileID
string or null

The id of the certificate profile. Required if TLS option is set to true

username
string or null

Username associated with the MQTT broker.

password
string or null

Password associated with the MQTT broker.

Array of objects

Array of topics and FilterChains which determine which matching Event messages are forwarded to which MQTT topics.

Responses
201

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/modules/mqtt
Request samples
application/json
{
  • "host": "10.20.0.1",
  • "port": 8883,
  • "TLS": true,
  • "CertificateProfileID": "MyCertificateProfileID",
  • "username": "string",
  • "password": "string",
  • "topics": [
    ]
}
Response samples
application/json
{
  • "ConnectionID": "0b214de7-8958-4956-8eed-28f9ba2c47c6",
  • "host": "10.20.0.1",
  • "port": 8883,
  • "TLS": true,
  • "CertificateProfileID": "MyCertificateProfileID",
  • "username": "string",
  • "topics": [
    ]
}

Get MQTT connection information.

SecurityOAuth2 or ApiKey
Request
path Parameters
ConnectionID
required
string

ID of the MQTT connection

Example: 0b214de7-8958-4956-8eed-28f9ba2c47c6
Responses
200

Response success.

401

Unauthorized access, invalid credentials were used.

404

Resource was not found.

get/modules/mqtt/{ConnectionID}
Request samples
Response samples
application/json
[
  • {
    }
]

Update MQTT connection settings.

SecurityOAuth2 or ApiKey
Request
path Parameters
ConnectionID
required
string

ID of the MQTT connection

Example: 0b214de7-8958-4956-8eed-28f9ba2c47c6
Request Body schema: application/json

Change the settings of a MQTT connection

host
string

IP or hostname of the MQTT broker.

port
integer
Default: 8883

Port of the MQTT service. (IANA registered ports (1883 unencrypted, 8883 TLS)

TLS
boolean
Default: true

Indicate if connection is using TLS

CertificateProfileID
string or null

The id of the certificate profile. Required if TLS option is set to true

username
string or null

Username associated with the MQTT broker.

password
string or null

Password associated with the MQTT broker.

Array of objects

Array of topics and FilterChains which determine which matching Event messages are forwarded to which MQTT topics.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/modules/mqtt/{ConnectionID}
Request samples
application/json
{
  • "host": "10.20.0.1",
  • "port": 8883,
  • "TLS": true,
  • "CertificateProfileID": "MyCertificateProfileID",
  • "username": "string",
  • "password": "string",
  • "topics": [
    ]
}
Response samples
application/json
{
  • "ConnectionID": "0b214de7-8958-4956-8eed-28f9ba2c47c6",
  • "host": "10.20.0.1",
  • "port": 8883,
  • "TLS": true,
  • "CertificateProfileID": "MyCertificateProfileID",
  • "username": "string",
  • "topics": [
    ]
}

Remove MQTT connection.

SecurityOAuth2 or ApiKey
Request
path Parameters
ConnectionID
required
string

ID of the MQTT connection

Example: 0b214de7-8958-4956-8eed-28f9ba2c47c6
Responses
200

Success response.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

delete/modules/mqtt/{ConnectionID}
Request samples
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Get MQTT certificate profiles.

SecurityOAuth2 or ApiKey
Responses
200

Response success.

401

Unauthorized access, invalid credentials were used.

404

Resource was not found.

get/modules/mqtt/certificate
Request samples
Response samples
application/json
[
  • {
    }
]

Create a new MQTT certificate profile

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Create a new MQTT certificate profile

name
string

The name of the certificate profile

ca
string

Server certificate (CA). This field is required

client
string or null

Client certificate

password
string or null

Client key

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/modules/mqtt/certificate
Request samples
application/json
{
  • "name": "Sample Certificate Name",
  • "ca": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVBekNDQXV1Z0F3SUJBZ0lVQlkxaGxDR3ZkajROaEJYa1ovdUxVWk5JTEF3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2daQXhDekFKQmdOVkJBWVRBa2RDTVJjd0ZRWURWUVFJREE1VmJtbDBaV1FnUzJsdVoyUnZiVEVPTUF3RwpBMVVFQnd3RlJHVnlZbmt4RWpBUUJnTlZCQW9NQ1UxdmMzRjFhWFIwYnpFTE1Ba0dBMVVFQ3d3Q1EwRXhGakFVCkJnTlZCQU1NRFcxdmMzRjFhWFIwYnk1dmNtY3hIekFkQmdrcWhraUc5dzBCQ1FFV0VISnZaMlZ5UUdGMFkyaHYKYnk1dmNtY3dIaGNOTWpBd05qQTVNVEV3TmpNNVdoY05NekF3TmpBM01URXdOak01V2pDQmtERUxNQWtHQTFVRQpCaE1DUjBJeEZ6QVZCZ05WQkFnTURsVnVhWFJsWkNCTGFXNW5aRzl0TVE0d0RBWURWUVFIREFWRVpYSmllVEVTCk1CQUdBMVVFQ2d3SlRXOXpjWFZwZEhSdk1Rc3dDUVlEVlFRTERBSkRRVEVXTUJRR0ExVUVBd3dOYlc5emNYVnAKZEhSdkxtOXlaekVmTUIwR0NTcUdTSWIzRFFFSkFSWVFjbTluWlhKQVlYUmphRzl2TG05eVp6Q0NBU0l3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFNRTBIS21JemZUT3drS0xUM1RISGUrT2JkaXphbVBnClVabUQ2NFRmM3pKZE5lWUdZbjRDRVhieVA2ZnkzdFdjOFMyYm9XNmR6ckg4U2RGZjl1bzMyMEdKQTlCN1UxRlcKVGUzeGRhL0xtM0pGZmFIamtXdzdqQndjYXVRWmpwR0lOSGFwSFJscGlDWnNxdUF0aE9neFc5U2dEZ1lsR3pFQQpzMDZwa0VGaU13K3FEZkxvL3N4RktCNnZRbEZla01lQ3ltakxDYk53UEp5cXloRm1QV3dpby9QRE1ydUJUelBICjNjaW9CbnJKV0tYYzNPalhkTEdGSk9majdwUDBqL2RyMkxINzJlU3Z2M1BRUUZsOTBDWlBGaHJDVWNSSFNTeG8KRTZ5akdPZG56N2Y2UHZlTElCNTc0a1FPUnd0OGVQbjB5aWRyVEMxaWN0aWtFRDNuSFloTVVPVUNBd0VBQWFOVApNRkV3SFFZRFZSME9CQllFRlBWVjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01COEdBMVVkSXdRWU1CYUFGUFZWCjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUwKQlFBRGdnRUJBR2E5a1MyMU43MFRoTTYvSGo5RDdtYlZ4S0xCalZXZTJUUHNHZmJsM3JFRGZaK09LUloyajZBQwo2cjdqYjRUWk8zZHpGMnA2ZGdicmxVNzFZLzRLMFRkeklqUmozY1EzS1NtNDFKdlVRMGhaL2MwNGlHRGcveFdmCitwcDU4bmZQQVl3dWVycnVQTldtbFN0V0FYZjBVVHFSdGc0aFFEV0J1VUZESlR1V3V1QnZFWHVkejc0ZWgvd0sKc013ZnUxSEZ2ank1WjBpTURVOFBVRGVwalZvbE9DdWU5YXNobFM0RUI1SUVDZFNSMlRJdG5BSWlJd2lteDgzOQpMZFVkUnVkYWZNdTVUNVhtYTE4Mk9DMC91L3hSbEVtK3R2S0dHbWZGY04wcGlxVmw4T3JTUEJnSWxiKzFJS0pFCm0vWHJpV3IvQ3E0aC9KZkI3TlRzZXpWc2xna0Jhb1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
  • "client": "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",
  • "password": "userpassword"
}
Response samples
application/json
{
  • "ID": "38ddf769-72a6-45c4-a782-efdda66a9a1b",
  • "name": "Sample Certificate Name"
}

Update MQTT connection settings.

SecurityOAuth2 or ApiKey
Request
path Parameters
CertificateProfileID
required
string

ID of the MQTT certificate profile

Example: 0b214de7-8958-4956-8eed-28f9ba2c47c6
Request Body schema: application/json

Update the settings of a MQTT certificate profile

name
string

The name of the certificate profile

ca
string

Server certificate (CA). This field is required

client
string or null

Client certificate

password
string or null

Client key

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/modules/mqtt/certificate/{CertificateProfileID}
Request samples
application/json
{
  • "name": "Sample Certificate Name",
  • "ca": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVBekNDQXV1Z0F3SUJBZ0lVQlkxaGxDR3ZkajROaEJYa1ovdUxVWk5JTEF3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2daQXhDekFKQmdOVkJBWVRBa2RDTVJjd0ZRWURWUVFJREE1VmJtbDBaV1FnUzJsdVoyUnZiVEVPTUF3RwpBMVVFQnd3RlJHVnlZbmt4RWpBUUJnTlZCQW9NQ1UxdmMzRjFhWFIwYnpFTE1Ba0dBMVVFQ3d3Q1EwRXhGakFVCkJnTlZCQU1NRFcxdmMzRjFhWFIwYnk1dmNtY3hIekFkQmdrcWhraUc5dzBCQ1FFV0VISnZaMlZ5UUdGMFkyaHYKYnk1dmNtY3dIaGNOTWpBd05qQTVNVEV3TmpNNVdoY05NekF3TmpBM01URXdOak01V2pDQmtERUxNQWtHQTFVRQpCaE1DUjBJeEZ6QVZCZ05WQkFnTURsVnVhWFJsWkNCTGFXNW5aRzl0TVE0d0RBWURWUVFIREFWRVpYSmllVEVTCk1CQUdBMVVFQ2d3SlRXOXpjWFZwZEhSdk1Rc3dDUVlEVlFRTERBSkRRVEVXTUJRR0ExVUVBd3dOYlc5emNYVnAKZEhSdkxtOXlaekVmTUIwR0NTcUdTSWIzRFFFSkFSWVFjbTluWlhKQVlYUmphRzl2TG05eVp6Q0NBU0l3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFNRTBIS21JemZUT3drS0xUM1RISGUrT2JkaXphbVBnClVabUQ2NFRmM3pKZE5lWUdZbjRDRVhieVA2ZnkzdFdjOFMyYm9XNmR6ckg4U2RGZjl1bzMyMEdKQTlCN1UxRlcKVGUzeGRhL0xtM0pGZmFIamtXdzdqQndjYXVRWmpwR0lOSGFwSFJscGlDWnNxdUF0aE9neFc5U2dEZ1lsR3pFQQpzMDZwa0VGaU13K3FEZkxvL3N4RktCNnZRbEZla01lQ3ltakxDYk53UEp5cXloRm1QV3dpby9QRE1ydUJUelBICjNjaW9CbnJKV0tYYzNPalhkTEdGSk9majdwUDBqL2RyMkxINzJlU3Z2M1BRUUZsOTBDWlBGaHJDVWNSSFNTeG8KRTZ5akdPZG56N2Y2UHZlTElCNTc0a1FPUnd0OGVQbjB5aWRyVEMxaWN0aWtFRDNuSFloTVVPVUNBd0VBQWFOVApNRkV3SFFZRFZSME9CQllFRlBWVjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01COEdBMVVkSXdRWU1CYUFGUFZWCjZ4QlVGUGlHS0R5bzVWMytIYmg0TjlZU01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUwKQlFBRGdnRUJBR2E5a1MyMU43MFRoTTYvSGo5RDdtYlZ4S0xCalZXZTJUUHNHZmJsM3JFRGZaK09LUloyajZBQwo2cjdqYjRUWk8zZHpGMnA2ZGdicmxVNzFZLzRLMFRkeklqUmozY1EzS1NtNDFKdlVRMGhaL2MwNGlHRGcveFdmCitwcDU4bmZQQVl3dWVycnVQTldtbFN0V0FYZjBVVHFSdGc0aFFEV0J1VUZESlR1V3V1QnZFWHVkejc0ZWgvd0sKc013ZnUxSEZ2ank1WjBpTURVOFBVRGVwalZvbE9DdWU5YXNobFM0RUI1SUVDZFNSMlRJdG5BSWlJd2lteDgzOQpMZFVkUnVkYWZNdTVUNVhtYTE4Mk9DMC91L3hSbEVtK3R2S0dHbWZGY04wcGlxVmw4T3JTUEJnSWxiKzFJS0pFCm0vWHJpV3IvQ3E0aC9KZkI3TlRzZXpWc2xna0Jhb1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
  • "client": "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",
  • "password": "userpassword"
}
Response samples
application/json
{
  • "ID": "38ddf769-72a6-45c4-a782-efdda66a9a1b",
  • "name": "Sample Certificate Name"
}

Remove MQTT certificate profile by ID.

SecurityOAuth2 or ApiKey
Request
path Parameters
CertificateProfileID
required
string

ID of the MQTT certificate profile

Example: 0b214de7-8958-4956-8eed-28f9ba2c47c6
Responses
200

Success response.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

delete/modules/mqtt/certificate/{CertificateProfileID}
Request samples
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Zone

The Zone module provides the ability to set certain zones within the 3D space of the Quantum RTLS system, which can conditionally trigger a series of actions from generating a log message, trigger an alarm on the device, or sending a request to a URI.

Get a listing of defined zones

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/modules/zones
Request samples
Response samples
application/json
[
  • {
    }
]

Create a new zone

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Create a new zone

Name
string

Friendly-name for a specific zone definition. Any JSON string is valid.

GeometryType
string

Specifies the shape of the Zone, which also dictates how the GeometryData is interpreted. 2D shapes extend infinitely to all positive and negative Z-coordinate values.

Enum: "sphere" "circle" "cuboid" "square" "cylinder" "polygon"
GeometryData
Array of integers non-empty

The schema for GeometryData depends on the GeometryType according to the following table:

GeometryType GeometryData
sphere [[center_point],[radius,0,0]]
circle [[center_point],[radius,0,0]]
cuboid [[origin],[length,width,height],[axis_l],[axis_w],[axis_h]]
square [[bottom_left],[length,width,0],[axis_l_x, axis_l_y, 0],[axis_w_x, axis_w_y, 0]]
cylinder [[origin],[axis],[height,radius,0]]
polygon [[vertex 1],[vertex 2],...[vertex N],[height,0,0],[axis]]
MobileOriginSource
string

The MAC address of the device to attach this zone's centre to, allowing the zone to become a moving centroid with latest device position as its centre.

AlertLevel
integer

Indicates the numeric alert level of the zone from the lowest priority (0) to the highest priority (+inf). This value determines what types of actions are taken on triggering, ranging from a site-wide alarm, device-level alarm, or a logged-only alarm.

Active
boolean
Default: true

Indicates whether the Zone is active or inactive. If a Zone is inactive, it will not cause any alarms even if devices enter the zone.

InclusionPolicy
string
Default: "all"

Specifies the default inclusion policy for devices which may trigger this zone. If set to all, any device that is not listed in the DeviceList is able to trigger the zone. If set to none, only devices listed in the DeviceList may trigger the zone.

Enum: "all" "none"
DeviceList
Array of strings

If InclusionPolicy is set to all, any device that is not listed in this list is able to trigger the zone. If InclusionPolicy to none, only devices listed in this list may trigger the zone.

Array of objects (ZoneAction)
IsTimed
boolean
Default: false

Indicates if the zone is a timed zone. If set, the StartTime and StopTime will be used to dictate when the zone is active.

StartTime
string <date-time>

The date and time indicating the start of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

StopTime
string <date-time>

The date and time indicating the end of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/modules/zones
Request samples
application/json
{
  • "Name": "Keep-out zone",
  • "GeometryType": "sphere",
  • "GeometryData": [
    ],
  • "MobileOriginSource": "00:11:22:33:44:55",
  • "AlertLevel": 3,
  • "Active": true,
  • "InclusionPolicy": "all",
  • "DeviceList": [
    ],
  • "ZoneActions": [],
  • "IsTimed": false,
  • "StartTime": "2019-08-24T14:15:22Z",
  • "StopTime": "2019-08-24T14:15:22Z"
}
Response samples
application/json
{
  • "SiteID": 501,
  • "ZoneID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
  • "Name": "Keep-out zone",
  • "GeometryType": "sphere",
  • "GeometryData": [
    ],
  • "MobileOriginSource": "00:11:22:33:44:55",
  • "CollidingDevices": [
    ],
  • "AlertLevel": 3,
  • "Active": true,
  • "InclusionPolicy": "all",
  • "DeviceList": [
    ],
  • "ZoneActions": [],
  • "IsGeometryLocked": false,
  • "IsTimed": false,
  • "StartTime": "2019-08-24T14:15:22Z",
  • "StopTime": "2019-08-24T14:15:22Z"
}

Get detailed information about a zone

SecurityOAuth2 or ApiKey
Request
path Parameters
ZoneID
required
string

ID of the zone

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

404

Resource was not found.

get/modules/zones/{ZoneID}
Request samples
Response samples
application/json
{
  • "SiteID": 501,
  • "ZoneID": "3F2504E0-4F89-11D3-9A0C-0305E82C3301",
  • "Name": "Keep-out zone",
  • "GeometryType": "sphere",
  • "GeometryData": [
    ],
  • "MobileOriginSource": "00:11:22:33:44:55",
  • "CollidingDevices": [
    ],
  • "AlertLevel": 3,
  • "Active": true,
  • "InclusionPolicy": "all",
  • "DeviceList": [
    ],
  • "ZoneActions": [],
  • "IsGeometryLocked": false,
  • "IsTimed": false,
  • "StartTime": "2019-08-24T14:15:22Z",
  • "StopTime": "2019-08-24T14:15:22Z"
}

Delete a zone

SecurityOAuth2 or ApiKey
Request
path Parameters
ZoneID
required
string

ID of the zone

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

delete/modules/zones/{ZoneID}
Request samples
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Update zone settings

SecurityOAuth2 or ApiKey
Request
path Parameters
ZoneID
required
string

ID of the zone

Request Body schema: application/json

Update a zone's settings

Name
string

Friendly-name for a specific zone definition. Any JSON string is valid.

GeometryType
string

Specifies the shape of the Zone, which also dictates how the GeometryData is interpreted. 2D shapes extend infinitely to all positive and negative Z-coordinate values.

Enum: "sphere" "circle" "cuboid" "square" "cylinder" "polygon"
GeometryData
Array of integers non-empty

The schema for GeometryData depends on the GeometryType according to the following table:

GeometryType GeometryData
sphere [[center_point],[radius,0,0]]
circle [[center_point],[radius,0,0]]
cuboid [[origin],[length,width,height],[axis_l],[axis_w],[axis_h]]
square [[bottom_left],[length,width,0],[axis_l_x, axis_l_y, 0],[axis_w_x, axis_w_y, 0]]
cylinder [[origin],[axis],[height,radius,0]]
polygon [[vertex 1],[vertex 2],...[vertex N],[height,0,0],[axis]]
MobileOriginSource
string

The MAC address of the device to attach this zone's centre to, allowing the zone to become a moving centroid with latest device position as its centre.

AlertLevel
integer

Indicates the numeric alert level of the zone from the lowest priority (0) to the highest priority (+inf). This value determines what types of actions are taken on triggering, ranging from a site-wide alarm, device-level alarm, or a logged-only alarm.

Active
boolean
Default: true

Indicates whether the Zone is active or inactive. If a Zone is inactive, it will not cause any alarms even if devices enter the zone.

InclusionPolicy
string
Default: "all"

Specifies the default inclusion policy for devices which may trigger this zone. If set to all, any device that is not listed in the DeviceList is able to trigger the zone. If set to none, only devices listed in the DeviceList may trigger the zone.

Enum: "all" "none"
DeviceList
Array of strings

If InclusionPolicy is set to all, any device that is not listed in this list is able to trigger the zone. If InclusionPolicy to none, only devices listed in this list may trigger the zone.

Array of objects (ZoneAction)
IsTimed
boolean
Default: false

Indicates if the zone is a timed zone. If set, the StartTime and StopTime will be used to dictate when the zone is active.

StartTime
string <date-time>

The date and time indicating the start of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

StopTime
string <date-time>

The date and time indicating the end of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/modules/zones/{ZoneID}
Request samples
application/json
{
  • "Name": "Keep-out zone",
  • "GeometryType": "sphere",
  • "GeometryData": [
    ],
  • "MobileOriginSource": "00:11:22:33:44:55",
  • "AlertLevel": 3,
  • "Active": true,
  • "InclusionPolicy": "all",
  • "DeviceList": [
    ],
  • "ZoneActions": [],
  • "IsTimed": false,
  • "StartTime": "2019-08-24T14:15:22Z",
  • "StopTime": "2019-08-24T14:15:22Z"
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Bulk create a bundle of zones

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Create all listed zones

Array
Name
string

Friendly-name for a specific zone definition. Any JSON string is valid.

GeometryType
string

Specifies the shape of the Zone, which also dictates how the GeometryData is interpreted. 2D shapes extend infinitely to all positive and negative Z-coordinate values.

Enum: "sphere" "circle" "cuboid" "square" "cylinder" "polygon"
GeometryData
Array of integers non-empty

The schema for GeometryData depends on the GeometryType according to the following table:

GeometryType GeometryData
sphere [[center_point],[radius,0,0]]
circle [[center_point],[radius,0,0]]
cuboid [[origin],[length,width,height],[axis_l],[axis_w],[axis_h]]
square [[bottom_left],[length,width,0],[axis_l_x, axis_l_y, 0],[axis_w_x, axis_w_y, 0]]
cylinder [[origin],[axis],[height,radius,0]]
polygon [[vertex 1],[vertex 2],...[vertex N],[height,0,0],[axis]]
MobileOriginSource
string

The MAC address of the device to attach this zone's centre to, allowing the zone to become a moving centroid with latest device position as its centre.

AlertLevel
integer

Indicates the numeric alert level of the zone from the lowest priority (0) to the highest priority (+inf). This value determines what types of actions are taken on triggering, ranging from a site-wide alarm, device-level alarm, or a logged-only alarm.

Active
boolean
Default: true

Indicates whether the Zone is active or inactive. If a Zone is inactive, it will not cause any alarms even if devices enter the zone.

InclusionPolicy
string
Default: "all"

Specifies the default inclusion policy for devices which may trigger this zone. If set to all, any device that is not listed in the DeviceList is able to trigger the zone. If set to none, only devices listed in the DeviceList may trigger the zone.

Enum: "all" "none"
DeviceList
Array of strings

If InclusionPolicy is set to all, any device that is not listed in this list is able to trigger the zone. If InclusionPolicy to none, only devices listed in this list may trigger the zone.

Array of objects (ZoneAction)
IsTimed
boolean
Default: false

Indicates if the zone is a timed zone. If set, the StartTime and StopTime will be used to dictate when the zone is active.

StartTime
string <date-time>

The date and time indicating the start of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

StopTime
string <date-time>

The date and time indicating the end of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

422

Invalid data was sent.

post/modules/zones/bulkCreate
Request samples
application/json
[
  • {
    }
]
Response samples
application/json
[
  • {
    }
]

Bulk update a bundle of zones

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

List of updated zone's settings

Array
Name
string

Friendly-name for a specific zone definition. Any JSON string is valid.

GeometryType
string

Specifies the shape of the Zone, which also dictates how the GeometryData is interpreted. 2D shapes extend infinitely to all positive and negative Z-coordinate values.

Enum: "sphere" "circle" "cuboid" "square" "cylinder" "polygon"
GeometryData
Array of integers non-empty

The schema for GeometryData depends on the GeometryType according to the following table:

GeometryType GeometryData
sphere [[center_point],[radius,0,0]]
circle [[center_point],[radius,0,0]]
cuboid [[origin],[length,width,height],[axis_l],[axis_w],[axis_h]]
square [[bottom_left],[length,width,0],[axis_l_x, axis_l_y, 0],[axis_w_x, axis_w_y, 0]]
cylinder [[origin],[axis],[height,radius,0]]
polygon [[vertex 1],[vertex 2],...[vertex N],[height,0,0],[axis]]
MobileOriginSource
string

The MAC address of the device to attach this zone's centre to, allowing the zone to become a moving centroid with latest device position as its centre.

AlertLevel
integer

Indicates the numeric alert level of the zone from the lowest priority (0) to the highest priority (+inf). This value determines what types of actions are taken on triggering, ranging from a site-wide alarm, device-level alarm, or a logged-only alarm.

Active
boolean
Default: true

Indicates whether the Zone is active or inactive. If a Zone is inactive, it will not cause any alarms even if devices enter the zone.

InclusionPolicy
string
Default: "all"

Specifies the default inclusion policy for devices which may trigger this zone. If set to all, any device that is not listed in the DeviceList is able to trigger the zone. If set to none, only devices listed in the DeviceList may trigger the zone.

Enum: "all" "none"
DeviceList
Array of strings

If InclusionPolicy is set to all, any device that is not listed in this list is able to trigger the zone. If InclusionPolicy to none, only devices listed in this list may trigger the zone.

Array of objects (ZoneAction)
IsTimed
boolean
Default: false

Indicates if the zone is a timed zone. If set, the StartTime and StopTime will be used to dictate when the zone is active.

StartTime
string <date-time>

The date and time indicating the start of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

StopTime
string <date-time>

The date and time indicating the end of the timed zone active timeframe. Only used when the IsTimed boolean is set to true.

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/modules/zones/bulkUpdate
Request samples
application/json
[
  • {
    }
]
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Bulk delete a bundle of zones

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Remove all zones that have the same zone IDs contained in the list

Array
string

Zone ID

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

put/modules/zones/bulkDelete
Request samples
application/json
[
  • "0bf650c2-3b03-447b-8b1a-4eacb09b04cb",
  • "2bcaef97-f6c7-4017-ba3b-a6b677d4b806"
]
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Activate zones

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Activate zones in the request body

Array
string

Zone ID

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

post/modules/zones/activate
Request samples
application/json
[
  • "0bf650c2-3b03-447b-8b1a-4eacb09b04cb",
  • "2bcaef97-f6c7-4017-ba3b-a6b677d4b806"
]
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Deactivate zones

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json

Deactivate zones in the request body

Array
string

Zone ID

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

post/modules/zones/deactivate
Request samples
application/json
[
  • "0bf650c2-3b03-447b-8b1a-4eacb09b04cb",
  • "2bcaef97-f6c7-4017-ba3b-a6b677d4b806"
]
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Add devices to a zone's device list

SecurityOAuth2 or ApiKey
Request
path Parameters
ZoneID
required
string

ID of the zone

Request Body schema: application/json

Add devices to a zone's device list

Array
string

Device ID (usually the device's MAC)

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

post/modules/zones/{ZoneID}/addDevices
Request samples
application/json
[
  • "00:11:22:33:44:55",
  • "66:77:88:99:00:AA"
]
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Remove devices from a zone's device list

SecurityOAuth2 or ApiKey
Request
path Parameters
ZoneID
required
string

ID of the zone

Request Body schema: application/json

Remove devices from a zone's device list

Array
string

Device ID (usually the device's MAC)

Responses
200

Response success

400

Malformed request.

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

422

Invalid data was sent.

post/modules/zones/{ZoneID}/removeDevices
Request samples
application/json
[
  • "00:11:22:33:44:55",
  • "66:77:88:99:00:AA"
]
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Get a listing of all available zone settings

SecurityOAuth2 or ApiKey
Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

get/modules/zones/settings
Request samples
Response samples
application/json
[
  • {
    }
]

Updates an existing global setting

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json
SettingName
string

Name of the setting

SettingValue
string

The currently set value for the setting in string format

Description
string

Name of the setting

DisplayName
string

Human readable setting name meant for display

IsActive
boolean

Indicates whether this setting is enabled or disabled

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

put/modules/zones/settings
Request samples
application/json
{
  • "SettingName": "SafetyBuffer",
  • "SettingValue": "0.15",
  • "Description": "Enabling this will create a buffer zone to alert an employee to an at risk zone entry",
  • "DisplayName": "Global Safety Buffer",
  • "IsActive": true
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Updates an existing device specific safety buffer setting

SecurityOAuth2 or ApiKey
Request
Request Body schema: application/json
property name*
additional property
number

The key value pair where the key is the device ID, and the value is the safety buffer radius in meters

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

put/modules/zones/settings/deviceSafetyBuffer
Request samples
application/json
{
  • "00:AA:BB:CC:DD:EE": 0.1
}
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

Delete a device safety buffer setting

SecurityOAuth2 or ApiKey
Request
path Parameters
address
required
string

Address of the device (usually it's MAC address)

Responses
200

Response success

401

Unauthorized access, invalid credentials were used.

403

Access forbidden. Current token does not have the necessary authority for the operation.

404

Resource was not found.

delete/modules/zones/settings/deviceSafetyBuffer/{address}
Request samples
Response samples
application/json
{
  • "status": 200,
  • "success": true
}

FAQ

Event Hub URI

Problem:

Uncertain about the URI used to connect to the Event Hub.

Solution:

  1. Ensure that the ECD is properly connected to the local network

  2. Plug a monitor onto the available ports on the ECD

  3. Boot up the ECD

  4. When fully started, the ECD base URI will be displayed on screen under the ZeroKey logo

  5. Knowing the base URI, the full Event Hub URI can be constructed following the following formats:

    • Non-secure: http://{base_uri}:33001/hubs/eventHub
    • Secure: https://{base_uri}:33000/hubs/eventHub

API endpoint base URI

Problem:

Uncertain about the base URI used to construct all API calls.

Solution:

  1. Ensure that the ECD is properly connected to the local network

  2. Plug a monitor onto the available ports on the ECD

  3. Boot up the ECD

  4. When fully started, the ECD base URI will be displayed on screen under the ZeroKey logo

  5. Knowing the base URI, the full all API endpoints can be constructed following the following formats:

    • Non-secure: http://{base_uri}:5000/v3/{specific_api_endpoints}
    • Secure: https://{base_uri}:5001/v3/{specific_api_endpoints}

Note: The specific API endpoints are case-sensitive, so please ensure that your URI fully matches what is provide in the API document.

Troubleshooting

Event Hub / API

Missing request body MIME type

Problem:

The QRTLS only accepts JSON formatted API request bodies. If a request is made without, or not using, JSON MIME types, the calls will be rejected.

Solution:

  1. Ensure that your API request specifies JSON MIME type

  2. Ensure that the data contains properly formatted JSON data string

Not receiving any event messages

Problem:

When an Event Hub connection is established without an Endpoint ID from the API connection call, or with a bad message filter, you will not receive any event messages from the Event Hub.

Solution:

  1. Obtain a valid OAuth2 token, or API key from QRTLS

    • Refer to the Authentication section
    • OAuth2 token has a validity of 30 minutes
    • Request for API key requires a prior OAuth2 token, but the key will not expire
  2. Initiate/update SignalR connection with the proper filters

  3. Ensure that you have started and is subscribed to the Event Hub events

function connectToEventHub(endpoint, id)
{
    var connection = new signalR.HubConnectionBuilder()
    .withUrl(eventHubUri, // Refer to the '1.1 Event Hub URI' section of this guide
    {
        accessTokenFactory: () => {
            return endpointId; // Returned from the API call in Step 2
        }
    })
    .build();
    
    // The event subscription, note that the string 'Event' is case sensitive
    connection.on("Event", function (message) {
        console.log(message);
    });

    // Start the connection
    connection.start().then(function () {
        console.log("Connected to Event Hub!");
    }).catch(function (err) {
        return console.error(err.toString());
    });
}

Wrong Event Hub connection message filter

Problem:

If the Event Hub connection filtered used does not include positional data, you will not receive any positional event messages.

Solution:

  1. Initiate or update the connection with the proper message filter
    • For defining a proper message filter, refer to the Filters schema section
    • For the filter templates, both the dashboard, and position_events filter will contain positional event messages
    • When defining the filter, either use the FilterTemplate options, or alternatively use the custom filter options. When a template is selected, the custom filter options will be ignored. Simply leave the FilterTemplate field empty, or set it to none to enable the custom filter options.

Hardware

Poor spatial calibration

Problem:

If the QRTLS has not been calibrated, or has a poor spatial calibration, the system will not be able to calculate valid positional data.

Solution:

  1. Follow Manual Setup guide that is physically included in all starter kits

Gateway not connected to the ECD

Problem:

The ZeroKey Gateway device is the key component in relaying data from the Anchor and Mobiles in the network. If it is not physically connected to the ECD, QRTLS will not have any data to generate the positional messages.

Solution:

  1. Find the USB to Micro B cable packaged with the kit

  2. Plug the Micro B end of the cable into the Gateway device

  3. Plug the USB end of the cable into the ECD

  4. Ensure that the built-in LED on the Gateway device lights up

Devices not powered on

Problem:

If either the Mobile or the Anchor devices are not turned on, there will not be sufficient data for the QRTLS to generate the positional messages.

Solution:

  1. Check the built-in LED on all Mobile and Anchor devices are lighting up
    • Press the button to turn the device back on if the lights are off
    • Charge the device if pressing the button does not affect the lights