NAV Navbar
http shell javascript

Introduction

Welcome to the CityPlatform API - the backend for CityFlow! You can use our API to access API endpoints, which can get information on various users, devices, and measurements in our database.

We have language bindings in Shell, HTTP and JavaScript! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.

Authentication

To authorize, use this code:

# With HTTP requests, you can just pass the correct Authorization header with each request
Authorization: Bearer {BEARER_TOKEN}
# With shell, you can just pass the correct header with each request
curl "https://api.cityflow.live"
  -H "Authorization: {BEARER_TOKEN}"

Make sure to replace BEARER_TOKEN with your API key from your CityFlow account.

CityPlatform uses API keys to allow access to the API. You can either login using user credentials to get token programmatically or you can register a new, dedicated CityPlatform API key at the CityFlow Settings page.

CityPlatform expects for the API key to be included in all API requests to the server in a header that looks like the following:

Authorization: Bearer {BEARER_TOKEN}

Users

Login

curl --request POST \
  --url https://api.cityflow.live/users/login \
  --header 'content-type: application/json' \
  --data '{
    "email": <EMAIL>,
    "password": <PASSWORD>
}'
POST /users/login HTTP/1.1
Content-Type: application/json
Host: api.cityflow.live

{
    "email": <EMAIL>,
    "password": <PASSWORD>
}
fetch("https://api.cityflow.live/users/login", {
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "body": {
    "email": <EMAIL>,
    "password": <PASSWORD>
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

{
  "email": "<EMAIL>",
  "first_name": "<FIRST_NAME>",
  "last_name": "<LAST_NAME>",
  "avatar": "<IMAGE_JPEG_BASE64>",
  "token": "{BEARER_TOKEN}"
}

This endpoint logs in on behalf of a user, letting the API retrieve user-specific access token.

HTTP Request

POST https://api.cityflow.live/users/login

JSON Parameters

Parameter Required Description
email true Email that user was registered with
password true Password used for logging in on CityFlow

Organizations

Get Organizations

curl --request GET \
  --url https://api.cityflow.live/organizations \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /organizations HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live
fetch("https://api.cityflow.live/organizations", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer <BEARER_TOKEN"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

[
  {
    "id": 1,
    "name": "MONTEM",
    "role": 4
  },
  {
    "id": 2,
    "name": "Copenhagen",
    "role": 4
  },
  {
    "id": 3,
    "name": "DONUT",
    "role": 4
  }
]

This endpoint retrieves all organizations related to the user including organization id, name and user role in specific organization.

HTTP Request

GET https://api.cityflow.live/organizations

Create Organization

curl --request POST \
  --url https://api.cityflow.live/organizations \
  --header 'authorization: Bearer {BEARER_TOKEN}' \
  --header 'content-type: application/json' \
  --data '{"organization_name": "Test Organization"}'
POST /organizations HTTP/1.1
Content-Type: application/json
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live

{"organization_name": "Test Organization"}
fetch("https://api.cityflow.live/organizations", {
  "method": "POST",
  "headers": {
    "content-type": "application/json",
    "authorization": "Bearer {BEARER_TOKEN}"
  },
  "body": {
    "organization_name": "Test Organization"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

{
  "id": 26,
  "role": 4
}

This endpoint creates an organization with specified name and returnsrelated to the user including organization id and user role in the newly created organization.

HTTP Request

POST https://api.cityflow.live/organizations

JSON Parameters

Parameter Required Description
name true Name of organization to be created

Devices

Get Devices

curl --request GET \
  --url https://api.cityflow.live/devices \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /devices HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live
fetch("https://api.cityflow.live/devices", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer {BEARER_TOKEN}"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

[
  {
    "id": "8DFC78",
    "type": 2,
    "location": 39,
    "latitude": 56.1271,
    "longitude": 10.1501,
    "roles": [
      4
    ],
    "permissions": [],
    "tags": []
  },
  {
    "id": "CDAFAC",
    "type": 2,
    "location": 57,
    "latitude": 56.2086,
    "longitude": 10.2444,
    "roles": [
      4
    ],
    "permissions": [],
    "tags": []
  },
  {
    "id": "8DFB80",
    "type": 2,
    "location": 116,
    "latitude": 56.153658,
    "longitude": 10.245545,
    "roles": [
      4
    ],
    "permissions": [],
    "tags": []
  }
]

This endpoint retrieves all devices related to the user including type, location id, latitude, longitude, tags, permissions and roles (Organization-based).

HTTP Request

GET https://api.cityflow.live/devices

Get Specific Device

curl --request GET \
  --url https://api.cityflow.live/devices \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /devices HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live
fetch("https://api.cityflow.live/devices", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer {BEARER_TOKEN}"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

[
  {
    "id": "8DFC78",
    "type": 2,
    "location": 39,
    "latitude": 56.1271,
    "longitude": 10.1501,
    "roles": [
      4
    ],
    "permissions": [],
    "tags": []
  },
  {
    "id": "CDAFAC",
    "type": 2,
    "location": 57,
    "latitude": 56.2086,
    "longitude": 10.2444,
    "roles": [
      4
    ],
    "permissions": [],
    "tags": []
  },
  {
    "id": "8DFB80",
    "type": 2,
    "location": 116,
    "latitude": 56.153658,
    "longitude": 10.245545,
    "roles": [
      4
    ],
    "permissions": [],
    "tags": []
  }
]

This endpoint retrieves all devices related to the user including type, location id, latitude, longitude, tags, permissions and roles (Organization-based).

HTTP Request

GET https://api.cityflow.live/devices

Get Device Types

curl --request GET \
  --url https://api.cityflow.live/devices/types \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /devices/types HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live


fetch("https://api.cityflow.live/devices/types", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer {BEARER_TOKEN}"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

[
  {
    "id": 1,
    "name": "CityProbe",
    "metadata": {
      "battery": 0,
      "sensors": [
        {
          "prop": "b",
          "name": "Battery Level",
          "unit": "%",
          "min": 0,
          "max": 100,
          "minColor": [
            255,
            0,
            0
          ],
          "maxColor": [
            0,
            255,
            0
          ]
        },
        {
          "prop": "h",
          "name": "Humidity",
          "unit": "%",
          "min": 0,
          "max": 100,
          "minColor": [
            255,
            255,
            0
          ],
          "maxColor": [
            0,
            0,
            255
          ]
        },
        {
          "prop": "l",
          "name": "Luminosity",
          "unit": "lx",
          "min": 0,
          "max": 100,
          "minColor": [
            0,
            0,
            0
          ],
          "maxColor": [
            255,
            255,
            255
          ]
        },
        {
          "prop": "r.avg",
          "name": "Rain",
          "unit": "dB(A)",
          "min": 0,
          "max": 100,
          "minColor": [
            255,
            255,
            0
          ],
          "maxColor": [
            0,
            0,
            255
          ]
        },
        {
          "prop": "p",
          "name": "Pressure",
          "unit": "hPa",
          "min": 0,
          "max": 1100,
          "minColor": [
            0,
            255,
            0
          ],
          "maxColor": [
            255,
            0,
            0
          ]
        },
        {
          "prop": "s.avg",
          "name": "Noise",
          "unit": "dB(A)",
          "min": 30,
          "max": 100,
          "minColor": [
            0,
            255,
            0
          ],
          "maxColor": [
            255,
            0,
            0
          ]
        },
        {
          "prop": "p2",
          "name": "Particle Pollution",
          "unit": "µg/m³",
          "min": -40,
          "max": 50,
          "minColor": [
            0,
            244,
            127
          ],
          "maxColor": [
            255,
            82,
            8
          ]
        },
        {
          "prop": "t",
          "name": "Temperature",
          "unit": "°C",
          "min": -40,
          "max": 50,
          "minColor": [
            0,
            0,
            255
          ],
          "maxColor": [
            255,
            0,
            0
          ]
        }
      ],
      "popup": {
        "values": [
          [
            {
              "sensor": 1
            },
            {
              "sensor": 2
            },
            {
              "sensor": 3
            }
          ],
          [
            {
              "sensor": 7
            },
            {
              "sensor": 6
            },
            {
              "sensor": 5
            }
          ]
        ]
      },
      "panel": {
        "values": [
          {
            "sensor": 6
          },
          {
            "sensor": 7
          },
          {
            "sensor": 3
          },
          {
            "sensor": 5
          },
          {
            "sensor": 1
          }
        ]
      }
    }
  }
]

This endpoint retrieves all device types related to the user including id, name, and metadata.

HTTP Request

GET https://api.cityflow.live/devices/types/{organization_id}

Path Parameters

Parameter Required Description
organization false For querying device types related to a specific organization

Measurements

Get Latest Measurements

curl --request GET \
  --url https://api.cityflow.live/measurements/latest \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /measurements/latest HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live
fetch("https://api.cityflow.live/measurements/latest", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer {BEARER_TOKEN}"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

{
  "1": [
    {
      "time": "2019-11-28T07:23:19.346Z",
      "b": 19.05,
      "c": 163,
      "firmware_version": "49",
      "h": 0,
      "l": 3353,
      "location": "8",
      "n": 170,
      "p": 0,
      "p1": 0,
      "p2": 0,
      "r.avg": -1673.1,
      "r.max": -757,
      "r.min": -1772,
      "r.sd": 169.71,
      "r.var": null,
      "s.avg": 81.16,
      "s.max": 81.65,
      "s.min": 77.6,
      "s.sd": 0.89,
      "s.var": null,
      "seq": 1203,
      "t": 0,
      "uv": null,
      "device_id": "49004d000d50483553343720"
    },
    {
      "time": "2019-11-28T07:43:59.124Z",
      "b": 41.19,
      "c": 48,
      "firmware_version": "48",
      "h": 30.92,
      "l": 297,
      "location": "12",
      "n": 50,
      "p": 484.5,
      "p1": 0,
      "p2": 0,
      "r.avg": 207.07,
      "r.max": 313,
      "r.min": 85,
      "r.sd": 37.66,
      "r.var": null,
      "s.avg": 48.22,
      "s.max": 57.89,
      "s.min": 45.85,
      "s.sd": 1.28,
      "s.var": null,
      "seq": 179,
      "t": -142.46,
      "uv": null,
      "device_id": "2b002a000f47373334363431"
    }
  ]
}

This endpoint retrieves all latest (within 45 minutes old) measurements related to the user including device id, timestamp and measurement data.

HTTP Request

GET https://api.cityflow.live/measurements/latest

Get Historical Measurements based on Device Type

curl --request GET \
  --url 'https://api.cityflow.live/measurements/history/device-type/{DEVICE_TYPE_ID}?from={ISO8601_TIMESTAMP}&to={ISO8601_TIMESTAMP}&resolution={RESOLUTION}' \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /measurements/history/device-type/{DEVICE_TYPE_ID}?from={ISO8601_TIMESTAMP}&to=ISO8601_TIMESTAMP>&resolution={RESOLUTION} HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live

fetch("https://api.cityflow.live/measurements/history/device-type/{DEVICE_TYPE_ID}?from={ISO8601_TIMESTAMP}&to={ISO8601_TIMESTAMP}&resolution={RESOLUTION}", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer {BEARER_TOKEN}"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

[
  {
    "time": "2019-11-27T08:20:00.000Z",
    "mean_b": 32.98,
    "mean_c": 144,
    "mean_h": 0,
    "mean_l": 502,
    "mean_n": 172,
    "mean_p": 0,
    "mean_p1": 0,
    "mean_p2": 0,
    "mean_r.avg": -8.19,
    "mean_r.max": 12,
    "mean_r.min": -1311,
    "mean_r.sd": 92.22,
    "mean_r.var": null,
    "mean_s.avg": 41.08,
    "mean_s.max": 79.05,
    "mean_s.min": 36.6,
    "mean_s.sd": 3.19,
    "mean_s.var": null,
    "mean_seq": 1142,
    "mean_t": 0,
    "mean_uv": null,
    "device_id": "49004d000d50483553343720",
    "location": "8"
  }, ...
]

This endpoint retrieves all historical measurements based on a device type id within the to and from parameters using the resolution parameter to bin measurements into specific sampling/averaging intervals.

An ISO8601 timestamp has the following format: 2019-11-27T12:00:23Z

For more information, see here ISO 8601

Resolution can e.g. be:

HTTP Request

GET https://api.cityflow.live/measurements/history/device-type/{device_type_id}?from={ISO8601_TIMESTAMP}&to={ISO8601_TIMESTAMP}&resolution={RESOLUTION}

Path Parameters

Parameter Required Description
to false An ISO8601 timestamp defining the start of interval
from false An ISO8601 timestamp defining the end of the interval
resolution false Defining the averaging resolution to downsample data if needed

Get Historical Measurements based on Location

curl --request GET \
  --url 'https://api.cityflow.live/measurements/history/location/{LOCATION_ID}?from={ISO8601_TIMESTAMP}&to={ISO8601_TIMESTAMP}&resolution={RESOLUTION}' \
  --header 'authorization: Bearer {BEARER_TOKEN}'
GET /measurements/history/location/{LOCATION_ID}?from={ISO8601_TIMESTAMP}&to={ISO8601_TIMESTAMP}&resolution=10m HTTP/1.1
Authorization: Bearer {BEARER_TOKEN}
Host: api.cityflow.live
fetch("https://api.cityflow.live/measurements/history/location/{LOCATION_ID}?from={ISO8601_TIMESTAMP}&to={ISO8601_TIMESTAMP}&resolution={RESOLUTION}", {
  "method": "GET",
  "headers": {
    "authorization": "Bearer {BEARER_TOKEN}"
  }
})
.then(response => {
  console.log(response);
})
.catch(err => {
  console.log(err);
});

The above command returns JSON structured like this:

[
  {
    "time": "2019-11-27T11:30:00.000Z",
    "mean_b": 14.66,
    "mean_c": 72,
    "mean_h": 100,
    "mean_l": 817,
    "mean_n": 69,
    "mean_p": 992.39,
    "mean_p1": 48,
    "mean_p2": 39,
    "mean_r.avg": 102.52,
    "mean_r.max": 266,
    "mean_r.min": 49,
    "mean_r.sd": 39.57,
    "mean_r.var": null,
    "mean_s.avg": 38.5,
    "mean_s.max": 40.13,
    "mean_s.min": 36.6,
    "mean_s.sd": 0.7,
    "mean_s.var": null,
    "mean_seq": 3424,
    "mean_t": 7.81,
    "mean_uv": null
  }, ...
]

This endpoint retrieves all historical measurements based on a location id within the to and from parameters using the resolution parameter to bin measurements into specific sampling/averaging intervals.

An ISO8601 timestamp has the following format: 2019-11-27T12:00:23Z

For more information, see here ISO 8601

Resolution can e.g. be:

HTTP Request

GET https://api.cityflow.live/measurements/latest

Path Parameters

Parameter Required Description
to false An ISO8601 timestamp defining the start of interval
from false An ISO8601 timestamp defining the end of the interval
resolution false Defining the averaging resolution to downsample data if needed

Errors

The CityPlatform API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
403 Forbidden -- The resource requested is hidden for administrators only.
404 Not Found -- The specified resource could not be found.
405 Method Not Allowed -- You tried to access a resource with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
410 Gone -- The kitten requested has been removed from our servers.
418 I'm a teapot.
429 Too Many Requests -- You're requesting too many resources! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.