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:
Method | Description | Object ID | Data |
---|---|---|---|
LIST | List all objects from endpoint | No | No |
OPEN | Open specific object | Yes | No |
UPDATE | Update specific object | Yes | Yes |
DELETE | Delete existing object | Yes | No |
INDEX | Retrieve search information about objects | Yes | No |
CREATE | Create object | No | Yes |
RUN | Execute method or flow | Yes | Yes |
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 Header | Query string |
---|---|
Flow-Auth-Token | token |
Flow-Request-ObjectId | objectid |
Flow-Request-Namespace | namespace |
Flow-Request-Method | method |
Flow-Request-Parameters | parameters |
Flow-Request-Parameter | parameter |
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"
}