Skip to main content

API Example Usage

The API powering Flow is based on Websockets where RPC Endpoints are published by Flow's various subsystems.

The API supports 7 methods, these are:

MethodDescriptionObject IDData
LISTList all objects from endpointNoNo
OPENOpen specific objectYesNo
UPDATEUpdate specific objectYesYes
DELETEDelete existing objectYesNo
INDEXRetrieve search information about objectsYesNo
CREATECreate objectNoYes
RUNExecute method or flowYesYes

Deepstream Websockets

All calls to Flow's APIs going through the websocket engine follow the structure:

{
"method": "LIST/OPEN/CREATE/UPDATE/DELETE/INDEX/RUN",
"objectid": "", // Needed for methods affecting existing objects
"token": "", // Authentication token
"namespace": "", // Namespace

"parameters": "", // Parameters
"data": {} // Needed for Create, Update & Run
}

Method & Token are always required regardless of the type of call made, objectid is only needed when the call involves a specific object in the database, e.g., Open, Update, Delete.

Data is required for operations where data in some form is to be saved as a result of the call.

Regardless of the type of call made or the type of response received, the structure is always the same, see examples of these responses below:

Fetching a device

Call to /inventory/device =>

{
"method": "OPEN",
"objectid": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"token": "Token generated by Authentication engine",
}

Response with error

{
"status": 0,
"success": false,
"message": "Object does not exist",
"errorcode": "DO_NOT_EXIST",
"dataType": "JSON",
"errorid": "7981f103-142e-41bf-ae39-ff1341de35f6"
}

Response with data

{
"status": 0,
"success": true,
"data": {
"id": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"created": "2017-07-10T09:23:50Z",
"updated": "2018-03-27T09:27:40Z",
"name": "5128v1.3 (Core-MGNT-switch)",
"..."
},
"dataType": "JSON"
}

The attribute "success": true/false is always present regardless of whether the call was successful or not.

HTTP

Flow's internal RPC endpoints are automatically published as an HTTP REST JSON API, which can be utilized to integrate third-party software with Flow. Responses from calls made over HTTP have the same structure as responses from Websockets since they are passed through without modification, the difference between calls over Websockets and HTTP is that all call data outside the data parameter is sent as HTTP Headers instead of in the object.

Provisional OpenAPI specification is available for each component as well as a complete all-in-one version on request. Contact fiber-support@bitvis.se to request access.

To make a call, you compose your URL in this way:

https://(address to flow gui)/api/(application name)/(rpc endpoint)/(object id)

e.g., https://flow.local/api/scheduler/scheduler/queue/ HTTP GET can be used for LIST, OPEN, and DELETE operations while HTTP POST can be used for CREATE and UPDATE operations.

Note that the / after queue is mandatory as it is part of the endpoint, ending without / assumes the last segment to be an object ID.

Everything in FlowRequest except for the data itself is either placed in headers or in the query string.

HTTP HeaderQuery string
Flow-Auth-Tokentoken
Flow-Request-ObjectIdobjectid
Flow-Request-Namespacenamespace
Flow-Request-Methodmethod
Flow-Request-Parametersparameters
Flow-Request-Parameterparameter

Authentication via HTTP API

The API handles two ways to authenticate, either HTTP Basic Auth or with a token. Both methods use headers.

HTTP Basic AUTH : Authorization: Basic base64(username:password)

Sending token through header: Flow-Auth-Token: Token från Autentiserinsmotorn

Sending parameters

Parameters are used with the LIST Flow-Request-Method for sorting, filtering, and pagination. There are two ways to send parameters, either as a list of key-value pairs or as a JSON object.

Example

Following is usage examples for the API, both via Websockets and HTTP.

Sorting, filtering, and pagination

Sorting, filtering, and pagination can be done in the same call. The following example shows what parameters to provide in order to sort by street number in ascending order, filter by city "Envik", and paginate the result to show only one item at a time.

{
"parameters": {
"sorting": true,
"sorting.by": "streetNumber",
"sorting.order": "ASC"
}
}
{
"parameters": {
"condition": true,
"condition.values": {
"items": [],
"subgroups": [
{
"items": [
{
"key": "city",
"operator": "EQUAL",
"value": "Envik"
}
],
"subgroups": [],
"logic": "AND"
}
],
"logic": "AND"
},
"sorting": true
}
}
{
"parameters": {
"pagination": true,
"pagination.size": 1,
"pagination.from": 0
}
}

Websockets

This shows sorting, filtering, and pagination in the same websocket call. They can be split into separate calls if needed, see examples for HTTP below.

Call to /address/address =>

{
"method": "LIST",
"token": "Token generated by Authentication engine",
"parameters": {
"sorting": true,
"sorting.by": "streetNumber",
"sorting.order": "ASC",
"condition": true,
"condition.values": {
"items": [],
"subgroups": [
{
"items": [
{
"key": "city",
"operator": "EQUAL",
"value": "Envik"
}
],
"subgroups": [],
"logic": "AND"
}
],
"logic": "AND"
},
"pagination": true,
"pagination.size": 1,
"pagination.from": 0
}
}

Response =>

{
"status": 0,
"success": true,
"data": [
{
"id": "b93aefc2-0bc7-4f87-a5ab-08c66326cee3",
"streetName": "Larss Gata",
"streetNumber": 6,
"streetLitteral": "G",
"postalCode": "12431",
"city": "Envik",
"..."
}
],
"count": 1,
"dataType": "JSON"
}

HTTP

The same call can be made via HTTP, but the parameters are sent in the Flow-Request-Parameter header. The parameters are sent as a JSON object instead of a list of key-value pairs.

The following examples show the parameters in separate calls, but they can be combined into one call as shown in the websocket example above.

Sorting

Call to /address/address =>

curl --location 'https://flow.local/api/address/address/address/' \
--header 'Flow-Request-Method: LIST' \
--header 'Flow-Request-Parameter: {"parameters": {"sorting": true,"sorting.by": "streetNumber","sorting.order": "ASC"}}' \
--header 'Authorization: Basic Zmxvd0BtYWludHJhYy5zZTpOT19QQVNTV09SRA=='

Response =>

{
"status": 0,
"success": true,
"data": [
{
"id": "d08be5ee-b207-4ee6-acf4-325dc0062d86",
"created": "2025-03-21T13:45:52+0100",
"attributes": {},
"streetName": "Övre Åkerallén",
"streetNumber": 4,
"...",
},
{
"id": "ec71cf34-3e01-4c79-b66d-af14db5d5c4c",
"created": "2025-03-21T13:45:52+0100",
"attributes": {},
"streetName": "Övre Ängsvägen",
"streetNumber": 5,
"...",
}
{
"...",
}
],
"count": 12,
"dataType": "JSON"
}
Filtering

Call to /address/address =>

curl --location 'https://flow.local/api/address/address/address/' \
--header 'Flow-Request-Method: LIST' \
--header 'Flow-Request-Parameter: {"parameters": {"condition": true,"condition.values": {"items": [], "subgroups": [{"items": [{"key": "city","operator": "EQUAL","value": "Envik"}],"subgroups": [],"logic": "AND"}], "logic": "AND"},"sorting": true}}' \
--header 'Authorization: Basic Zmxvd0BtYWludHJhYy5zZTpOT19QQVNTV09SRA=='

Response =>

{
"status": 0,
"success": true,
"data": [
{
"id": "b93aefc2-0bc7-4f87-a5ab-08c66326cee3",
"streetName": "Larss Gata",
"streetNumber": 6,
"streetLitteral": "G",
"postalCode": "12431",
"city": "Envik",
"..."
}
],
"count": 1,
"dataType": "JSON"
}
Pagination

Call to /address/address =>

curl --location 'https://flow.local/api/address/address/address/' \
--header 'Flow-Request-Method: LIST' \
--header 'Flow-Request-Parameter: {"parameters": {"pagination": true, "pagination.size": 1,"pagination.from": 0}}' \
--header 'Authorization: Basic Zmxvd0BtYWludHJhYy5zZTpOT19QQVNTV09SRA=='

Response =>

{
"status": 0,
"success": true,
"data": [
{
"id": "b46bb7bf-c88e-439a-a396-87bbda0ffad9",
"created": "2025-03-21T13:45:51+0100",
"attributes": {},
"streetName": "Östra Backgärdet",
"streetNumber": 222,
"streetLitteral": "A",
"postalCode": "39927",
"city": "Götefred",
"countryCode": "SE",
"apartmentNo": "1501",
"refType": "vgvytmuane",
"latitude": -76.4406,
"longitude": 127.0144,
"segment": [
"3b1d3419-c263-4ab1-abeb-a2df32a84855"
],
"_name": ""
}
],
"count": 12,
"dataType": "JSON"
}

Fetch a device

Websockets

Call to /inventory/device =>

{
"method": "OPEN",
"objectid": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"token": "Token generated by Authentication engine",
}

Response =>

{
"status": 0,
"success": true,
"data": {
"id": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"created": "2017-07-10T09:23:50Z",
"updated": "2018-03-27T09:27:40Z",
"name": "5128v1.3 (Core-MGNT-switch)",
"..."
},
"dataType": "JSON"
}

HTTP

GET flow.local/api/inventory/inventory/device
headers
Flow-Auth-Token: "Token generated by Authentication engine"
Flow-Request-ObjectId: "3a472a78-4e3e-4858-8acc-eb754f9d1328"
Flow-Request-Method: "OPEN"

Response =>

{
"status": 0,
"success": true,
"data": {
"id": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"created": "2017-07-10T09:23:50Z",
"updated": "2018-03-27T09:27:40Z",
"name": "5128v1.3 (Core-MGNT-switch)",
"..."
},
"dataType": "JSON"
}

Update a device

Websockets

Call to /inventory/device =>

{
"method": "UPDATE",
"objectid": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"token": "Token generated by Authentication engine",
"data": {
"name": "New name for switch"
}
}

Response =>

{
"status": 0,
"success": true,
"data": {
"id": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"created": "2017-07-10T09:23:50Z",
"updated": "2018-03-27T09:27:40Z",
"name": "New name for switch",
"..."
},
"dataType": "JSON"
}

HTTP

POST flow.maintrac.net/api/inventory/inventory/device
headers
Flow-Auth-Token: "Token generated by Authentication engine"
Flow-Request-ObjectId: "3a472a78-4e3e-4858-8acc-eb754f9d1328"
Flow-Request-Method: "UPDATE"
body
{
"name": "New name for switch"
}

Response =>

{
"status": 0,
"success": true,
"data": {
"id": "3a472a78-4e3e-4858-8acc-eb754f9d1328",
"created": "2017-07-10T09:23:50Z",
"updated": "2018-03-27T09:27:40Z",
"name": "New name for switch",
"..."
},
"dataType": "JSON"
}