Summary
The Smart Citizen API is a publicly available interface allowing anyone to develop applications on top of the Smart Citizen platform. For more general and hardware information check the documentation.
# Shell example
# In the shell examples we use either `curl` or the `http`
// Javascript example
# The json responses will look something like this:
[
{
"example_response":"example_value"
}
]
Schema
In a general sense, any user can own as many device as needed. Each device represents a "real" device, containing sensors, which perform measurements. A device in a real world can be registered multiple times in the API, but it will only store data in one device. In addition, user can create experiments, which are collection of devices with a certain purpose. This feature is currently experimental!
All API access is over HTTPS and accessed via api.smartcitizen.me
. Some overall characteristics to bear in mind:
- Blank fields are included as
null
instead of being omitted. - Obviously, some items are filtered by the API if your response are not authorized. See authhentication.
- All timestamps are returned in ISO 8601 format, non-localised:
YYYY-MM-DDTHH:MM:SSZ
.
Root Endpoint
You can issue a GET
request to the root endpoint to get all the endpoint categories that the API supports. From all the possible endpoints, you will mostly care about devices, measurements, sensors and users.
$ curl https://api.smartcitizen.me
http GET https://api.smartcitizen.me/v0/
// Run this in your browser console
fetch('https://api.smartcitizen.me/v0/')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});
HTTP/1.1 200 OK
{
"notice":"Welcome. The old API has been removed.",
"api_documentation_url":"https://developer.smartcitizen.me",
"current_user_url":"https://api.smartcitizen.me/v0/me",
"devices_url":"https://api.smartcitizen.me/v0/devices",
"measurements_url":"https://api.smartcitizen.me/v0/measurements",
"sensors_url":"https://api.smartcitizen.me/v0/sensors",
"users_url":"https://api.smartcitizen.me/v0/users",
"tags_url":"https://api.smartcitizen.me/v0/tags",
"tags_sensors_url":"https://api.smartcitizen.me/v0/tag_sensors",
"version_git":"1.1.5\n"
}
Versioning
By default and, for now, all requests receive the v0 version of the API. We encourage you to explicitly request this version via the URL or the HTTP Accept header.
endpoint | |
---|---|
BAD | https://api.smartcitizen.me/users |
GOOD | https://api.smartcitizen.me/v0/users |
Accept: application/vnd.smartcitizen; version=0,application/json
Authentication
There are 2 ways you can access the API. OAuth 2.0 is the recommended method.
OAuth 2.0
# Send authenticated POST for username 'user1', which should return the 'access_token'
$ curl -XPOST https://api.smartcitizen.me/v0/sessions -d "username=user1" -d "password=password"
# OAuth2 Token (sent as a parameter)
$ curl -G https://api.smartcitizen.me/v0/me?access_token=OAUTH-TOKEN
# OAuth2 Token (sent in a header)
$ curl -H "Authorization: Bearer OAUTH-TOKEN" https://api.smartcitizen.me/v0/me
You can obtain a general access_key
by sending an authenticated POST request to https://api.smartcitizen.me/v0/sessions
A basic example resides here https://example.smartcitizen.me and its source code is here https://github.com/johnrees/smartcitizen-oauth-example.
HTTP Basic Auth
# Add a base64 encoded hash of 'username:password' in the header
curl 'https://api.smartcitizen.me/v0/me' -H 'Authorization: Basic am9objpzbWFydHBhc3M='
# NOT RECOMMENDED - add username and password in the header
curl 'https://api.smartcitizen.me/v0/me' --user username:password
Filtering Responses
Pagination
$ curl --include 'https://api.smartcitizen.me/v0/users?page=5'
HTTP/1.1 200 OK
Link: <https://api.smartcitizen.me/v0/users?page=1>; rel="first",
<https://api.smartcitizen.me/v0/users?page=173>; rel="last",
<https://api.smartcitizen.me/v0/users?page=6>; rel="next",
<https://api.smartcitizen.me/v0/users?page=4>; rel="prev"
Total: 4321
Per-Page: 25
Most endpoints that return more than a single result e.g. /v0/users
, v0/devices
will return blocks of the result set that can be manipulated using the following parameters.
Parameter | Default | Description |
---|---|---|
page integer |
1 | page |
per_page integer |
25 | page |
The headers will include links to the Total
results count, number of results shown Per-Page
and first
, last
, next
and previous
results.
Global Search
curl -XGET https://api.smartcitizen.me/v0/search?q=barcelona
HTTP/1.1 200 OK
[
{
"id": 506,
"type": "Device",
"name": "Barceloneta Sensor",
"description": "Barcelona sensor place at a 7th floor in front of the beach. Working on different batteries to have more autonomy outdoors. Next: Solar Panel!",
"owner_id": 3,
"owner_username": "tomasdiez",
"city": "Barcelona",
"country_code": "ES"
}
...
To search both Users and Devices at the same time you can use the global search endpoint.
Required Parameters
Parameter | Description |
---|---|
q string |
Query string |
Response
There can be two types of object included in the response array, Devices and Users.
Device Object
Parameter | Description |
---|---|
id integer |
Unique ID for the device |
name string |
Name of the device |
owner_id integer |
Unique ID of the device's owner |
owner_username string |
Unique username of the device's owner |
city string |
City the device is in |
country_code string |
Alpha-2 country code of the device |
User Object
Parameter | Description |
---|---|
id integer |
Unique ID for the user |
username string |
Unique username of the user |
avatar string |
URL of the users avatar |
city string |
City the user is in |
country_code string |
Alpha-2 country code of the user |
Basic Searching
Similar to the pagination, you can filter and sort most responses that return more than one result. This is done with the Ransack library. You can query different endpoints and filter them by using search matchers.
https://github.com/activerecord-hackery/ransack/wiki/Basic-Searching
For information about the Search Matchers, check the Ransack documentation.
Keys for devices
Key |
---|
id |
name |
description |
owner_username |
owner_id |
created_at |
updated_at |
last_recorded_at |
state |
exposure |
kit_id |
geohash |
uuid |
Keys for users
Key |
---|
id |
username |
created_at |
updated_at |
city |
country_code |
uuid |
Examples
Query | Type | Value | Description |
---|---|---|---|
/users?q[username_eq]=adam | string | adam | Users where first name equals 'Adam' |
/devices?q[owner_id_eq]=1 | integer | 1 | Devices where owner ID equals 1 |
/devices?q[tags_name_in]=Barcelona | string | Barcelona | Devices which have the tag 'Barcelona' (case sensitive). |
/devices?with_tags=Barcelona|Amsterdam | string | Barcelona|Amsterdam | Devices which have ANY of the tags separated by PIPE | |
/devices?q[postprocessing_id_not_null]=1 | integer | 1 | Devices where postprocessing is not_null |
/sensors?q[id_lt]=100 | integer | 100 | Sensors where ID less than 100 |
/users?q[username_cont]=sck | string | sck | Users where username contains 'sck' |
Sorting Results
You can order results with the q[sort]
parameter
Parameter | Value | Description |
---|---|---|
/users?q[sort]=username%20asc string |
username asc | Users ordered by username in ASCENDING order |
/devices?q[sort]=id%20desc integer |
id desc | Devices ordered by id in DESCENDING order |
Pretty Printing
# Pretty Response
curl "https://api.smartcitizen.me/v0/sensors/10?pretty=true"
Result:
{
"id" : 10,
"name" : "Battery",
"description" : "Custom Circuit",
"unit" : "%",
"created_at" : "2015-02-02T18:18:00.276Z",
"updated_at" : "2015-02-02T18:18:00.276Z"
}
You can format responses so that they are easier to read by adding pretty=true
to a request.
Users
Add a User
POST https://api.smartcitizen.me/v0/users
http POST https://api.smartcitizen.me/v0/users email=testing@test.com password=testpass username=testinguser
HTTP/1.1 201 Created
{
"avatar": "http://smartcitizen.s3.amazonaws.com/avatars/default.svg",
"devices": [],
"email": "[FILTERED]",
"id": 3858,
"joined_at": "2015-07-31T10:20:27Z",
"location": {
"city": null,
"country": null,
"country_code": null
},
"role": "citizen",
"updated_at": "2015-07-31T10:20:27Z",
"url": null,
"username": "testinguser",
"uuid": null
}
Most actions on the API require authenticated access. To obtain an OAuth 2.0 access_token
the first step is to have a user account.
Parameter | Required? | Description |
---|---|---|
email string |
✓ | Email address of the user |
username string |
✓ | Username of the user |
password string |
✓ | Password of the user |
city string |
City where the user is located | |
country_code string |
2 letter country-code of the user | |
url string |
Webpage of the user |
Get Current User (me)
GET https://api.smartcitizen.me/v0/me
http GET https://api.smartcitizen.me/v0/me access_token=123456789
HTTP/1.1 200 OK
{
"avatar": "http://images.smartcitizen.me/s100/feca2180/firewatch-4.jpg",
"devices": [
{
"added_at": "2015-07-31T10:11:09Z",
"description": "new description",
"id": 1816,
"kit_id": null,
"last_reading_at": null,
"latitude": null,
"longitude": null,
"mac_address": "00:0a:95:9d:68:16",
"name": "my sck",
"state": "never_published",
"system_tags": [
"new",
"offline"
],
"updated_at": "2015-07-31T10:15:06Z",
"uuid": "cb480089-c000-4e69-96c0-ad6378f3a537"
}
],
"email": "john@bitsushi.com",
"id": 2997,
"joined_at": "2015-02-02T15:17:28Z",
"location": {
"city": "Barcelona",
"country": "Spain",
"country_code": "ES"
},
"role": "citizen",
"updated_at": "2015-07-31T10:12:46Z",
"url": "http://www.google.com",
"username": "john",
"uuid": "feca2180-d0dd-49fd-8815-ec59ca6d48f6"
}
Used to retrieve information about the currently authenticated user. It returns a detailed representation of the user.
Field | Description |
---|---|
id* integer |
Autoincrementing unique ID for the user |
uuid* uuid |
Unique ID for the user |
role* string |
There are currently three different roles: citizen , researcher and admin . See role. |
username* string |
Username of the user |
profile_picture* file |
Upload the image that represents the user. It will return a Rails active_storage link to the asset |
url string |
Webpage of the user |
location.city string |
City in which the user is located |
location.country string |
Full country name. Automatically generated from country_code, using this data |
location.country_code string |
2 letter country-code of the user |
updated_at* datetime |
The date and time that the user updated data on the platform |
email string |
Email address of the authenticated user, will be [FILTERED] for unauthenticated requests |
forwarding_token string |
Hash containing a forwarding secret topic to be used in data forwarding |
forwarding_username string |
Hash containing a forwarding secret username to be used in data forwarding |
devices array |
Array of devices that the user owns on the platform |
Roles
The role
defines privileges of the user, for which citizen
is the default role. admin
accounts have full access to the platform, while researchers
can enable data forwarding for the devices they own. This differentiation is done to allow experimental features, such as forwarding, to be tested in a more restricted environments and see how they scale. researcher
roles do not have throttling
on API requests, while citizen
requests are limited to 90 requests/minute. Beyond these two differences, there is no other impact on the data or actions allowed. You can write us to have researcher
access at our support mail.
Update Current User
PATCH https://api.smartcitizen.me/v0/me
http PATCH https://api.smartcitizen.me/v0/me access_token=randomToken1234
HTTP/1.1 200 OK
{
"avatar": "http://images.smartcitizen.me/s100/feca2180/firewatch-4.jpg",
"devices": [
{
"added_at": "2015-07-31T10:11:09Z",
"description": null,
"id": 1816,
"kit_id": null,
"last_reading_at": null,
"latitude": null,
"longitude": null,
"mac_address": "00:0a:95:9d:68:16",
"name": "my sck",
"state": "never_published",
"system_tags": [
"new",
"offline"
],
"updated_at": "2015-07-31T10:11:09Z",
"uuid": "cb480089-c000-4e69-96c0-ad6378f3a537"
}
],
"email": "john@bitsushi.com",
"id": 2997,
"joined_at": "2015-02-02T15:17:28Z",
"location": {
"city": "Barcelona",
"country": "Spain",
"country_code": "ES"
},
"role": "citizen",
"updated_at": "2015-07-31T10:12:46Z",
"url": "http://www.google.com",
"username": "john",
"uuid": "feca2180-d0dd-49fd-8815-ec59ca6d48f6"
}
An authenticated user can update their own details. They have the same parameters used as adding a user.
Change an Avatar
This is the only supported way, using Rails Active Storage:
curl -XPATCH 'https://api.smartcitizen.me/v0/me?access_token=MYAPITOKEN' --form "profile_picture=@mypicture.jpeg"
Reset a Password
http POST https://api.smartcitizen.me/v0/password_resets?username=testing
HTTP/1.1 200 OK
{
"message": "Password Reset Instructions Delivered"
}
# password reset email has been sent to user: testing
Step 1 of 4
Initiate the password reset.
POST https://api.smartcitizen.me/v0/password_resets?email_or_username=username
or
POST https://api.smartcitizen.me/v0/password_resets?email_or_username=email
Step 2 of 4
An email is sent to the user, containing a PASSWORD_RESET_TOKEN
.
Step 3 of 4
Return the User(username=USERNAME)
object.
POST https://api.smartcitizen.me/v0/password_resets/:password_reset_token
Step 4 of 4
Set the new password.
PATCH https://api.smartcitizen.me/v0/password_resets/:password_reset_token?password=password
Get All Users
GET https://api.smartcitizen.me/v0/users
http GET https://api.smartcitizen.me/v0/users
HTTP/1.1 200 OK
[
{
"id": 1,
"uuid": "4725977d-0490-4984-b5a4-df2a483a85ae",
"role": "admin",
"username": "testing",
"avatar": "https://images.smartcitizen.me/s100/avatars/472/1arck5q.firewatch-6.jpg",
"url": null,
"location": {
"city": null,
"country": null,
"country_code": null
},
"joined_at": "2015-01-27T18:43:26Z",
"updated_at": "2015-07-30T09:59:28Z",
"email": "[FILTERED]",
"devices": [
{
"id": 1148,
"uuid": "dd4b6f66-5b51-44d0-a9de-e7fd1999287d",
"mac_address": "[FILTERED]",
"name": null,
"description": null,
"latitude": 52.3079989,
"longitude": 4.97154509999996,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:49Z",
"updated_at": "2015-05-25T07:31:28Z"
},
{
"id": 1762,
"uuid": "f119ff40-348c-4827-b266-06c3a4e5fbe3",
"mac_address": "[FILTERED]",
"name": "RyanLim",
"description": "Tiong Bahru",
"latitude": 1.28645,
"longitude": 103.826917,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:51Z",
"updated_at": "2015-05-25T07:31:29Z"
},
{
"id": 344,
"uuid": "c6b1792d-8a0d-44f0-bce3-89cb6819dac5",
"mac_address": "[FILTERED]",
"name": "SmartCitizenSk",
"description": null,
"latitude": 53.406754,
"longitude": -2.158843,
"kit_id": 2,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:47Z",
"updated_at": "2015-05-25T07:31:27Z"
},
{
"id": 1242,
"uuid": "da84118a-4e49-4c59-baf1-f622a10b69de",
"mac_address": "[FILTERED]",
"name": null,
"description": null,
"latitude": 52.3079989,
"longitude": 4.97154509999996,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:49Z",
"updated_at": "2015-05-25T07:31:28Z"
},
{
"id": 860,
"uuid": "937c78eb-ec19-47c0-a9ad-1be6cec4b8d6",
"mac_address": "[FILTERED]",
"name": "Bwired.nl",
"description": null,
"latitude": 51.7242901136958,
"longitude": 5.30086557678224,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:48Z",
"updated_at": "2015-05-25T07:31:27Z"
},
{
"id": 1749,
"uuid": "bb26425d-30ae-4d9b-a6a6-7b828c8ed1ba",
"mac_address": "[FILTERED]",
"name": "Yongin1",
"description": null,
"latitude": 37.2410864,
"longitude": 127.1775537,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:51Z",
"updated_at": "2015-05-25T07:31:28Z"
},
{
"id": 747,
"uuid": "42beffb0-76b4-4e75-bbd3-2636c5be90fd",
"mac_address": "[FILTERED]",
"name": "AroundMe HQ",
"description": null,
"latitude": 45.4319105,
"longitude": 7.80372020000004,
"kit_id": 2,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:48Z",
"updated_at": "2015-05-25T07:31:29Z"
},
{
"id": 1149,
"uuid": "6849e0dd-8265-45b8-8e74-79af064cb092",
"mac_address": "[FILTERED]",
"name": "2e kekerstraat",
"description": null,
"latitude": 52.3079989,
"longitude": 4.97154509999996,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:49Z",
"updated_at": "2015-05-25T07:31:29Z"
},
{
"id": 1006,
"uuid": "cb1d8723-66b0-4cae-95c4-4849e513727b",
"mac_address": "[FILTERED]",
"name": "SCARNING",
"description": null,
"latitude": 52.6724249,
"longitude": 0.885390000000029,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:49Z",
"updated_at": "2015-05-25T07:31:29Z"
},
{
"id": 1760,
"uuid": "63a923c2-508e-4ac5-b90c-73b8b45561fd",
"mac_address": "[FILTERED]",
"name": null,
"description": null,
"latitude": 1.2800945,
"longitude": 103.8509491,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:51Z",
"updated_at": "2015-05-25T07:31:29Z"
},
{
"id": 605,
"uuid": "3a86d052-28b4-4ecc-9293-3c5aa40d6a30",
"mac_address": "[FILTERED]",
"name": "MySmartCitizenBoard",
"description": null,
"latitude": 42.1969689,
"longitude": -88.0934108,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:48Z",
"updated_at": "2015-05-25T07:31:31Z"
},
{
"id": 1473,
"uuid": "8f7724af-50e8-4967-869c-4ff94e016023",
"mac_address": "[FILTERED]",
"name": "Village Green Drive",
"description": null,
"latitude": 40.9253764,
"longitude": -73.0473284,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:50Z",
"updated_at": "2015-05-25T07:31:31Z"
},
{
"id": 1147,
"uuid": "e211ea4c-580a-410d-9308-a328aae4d98b",
"mac_address": "[FILTERED]",
"name": "Guli's Sensors",
"description": "This is the ultimate SCK",
"latitude": 46.8037168264815,
"longitude": -71.2302180070495,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:49Z",
"updated_at": "2015-05-25T07:31:31Z"
},
{
"id": 1376,
"uuid": "0ac3d295-670f-4661-a165-1483ff95bde4",
"mac_address": "[FILTERED]",
"name": "KitTest",
"description": null,
"latitude": 45.6669011,
"longitude": 12.243039,
"kit_id": 3,
"state": "has_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": "2015-04-27T15:30:20Z",
"added_at": "2015-02-02T15:59:50Z",
"updated_at": "2015-05-25T08:43:14Z"
}
]
}
...
This endpoint retrieves all users. This returns the same fields as the me endpoint if authenticated and authorized. Private fields are returned as [FILTERED]
.
Get a User
GET https://api.smartcitizen.me/v0/users/(:id|:username)
http https://api.smartcitizen.me/v0/users/2
HTTP/1.1 200 OK
{
"id": 2,
"uuid": "fdbc41c4-ba01-4bfc-b850-edda889bff2e",
"role": "citizen",
"username": "alex",
"avatar": "http://smartcitizen.s3.amazonaws.com/avatars/default.svg",
"url": null,
"location": {
"city": null,
"country": null,
"country_code": null
},
"joined_at": "2015-02-02T15:54:37Z",
"updated_at": "2015-07-21T12:20:54Z",
"email": "[FILTERED]",
"devices": [
{
"id": 1357,
"uuid": "791e06b0-d068-4f62-8701-4e41cf15e38a",
"mac_address": "[FILTERED]",
"name": "Citizen Science Kit #1",
"description": "Test Kit for the Innovation Lab Kosovo, within the event Science for change / Citizen Science.",
"latitude": 42.5813722,
"longitude": 20.88935,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:50Z",
"updated_at": "2015-05-25T07:31:28Z"
},
{
"id": 1360,
"uuid": "206296e5-7837-4587-af91-5b782db42135",
"mac_address": "[FILTERED]",
"name": "Citizen Science Pristina #2",
"description": "this kit is to monitor the air quality in the area of Pristina and is part of the science for change initiative",
"latitude": 42.7145797355173,
"longitude": 21.1464852426758,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:50Z",
"updated_at": "2015-05-25T07:31:28Z"
},
{
"id": 339,
"uuid": "c7201a30-da4b-4dec-8042-3d30da1b3363",
"mac_address": "[FILTERED]",
"name": "Roma Maker Faire",
"description": "SmartCitizen Kit exhibited in the Maker Faire in Rome\r\n00:06:66:21:17:58",
"latitude": 41.8343,
"longitude": 12.473442,
"kit_id": 2,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:47Z",
"updated_at": "2015-05-25T07:31:28Z"
},
{
"id": 1402,
"uuid": "ddd06451-b847-4972-965a-96eef438282e",
"mac_address": "[FILTERED]",
"name": "test for Fab10",
"description": "mhdvsajhgdasjhgasdjhg",
"latitude": 41.3965424157754,
"longitude": 2.19476096466298,
"kit_id": 3,
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:50Z",
"updated_at": "2015-05-25T07:31:29Z"
},
{
"id": 12,
"uuid": "21631212-8633-450e-bd44-f36202d864f6",
"mac_address": "[FILTERED]",
"name": "Parisien Sensor",
"description": "Test from Paris waking up",
"latitude": 48.84676,
"longitude": 2.41442,
"kit_id": 2,
"state": "never_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:46Z",
"updated_at": "2015-05-25T07:31:31Z"
}
]
}
This endpoint retrieves a specific user. If authenticated, it will return the same fields as the me endpoint if authenticated and authorized. Private fields are returned as [FILTERED]
.
URL Parameters
Parameter | Description |
---|---|
ID or username | The ID (int) or username (string) of the user to retrieve. |
Devices
Get a Device
GET https://api.smartcitizen.me/v0/devices/:id
http GET https://api.smartcitizen.me/v0/devices/1616
HTTP/1.1 200 OK
{
"id": 1616,
"uuid": "85543ca2-e543-4351-9122-98756d50e6b1",
"name": "Orchid Surf Stay Bali",
"description": "Located at the pool area of the hotel ",
"state": "has_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": "2015-07-16T08:53:16Z",
"added_at": "2015-02-02T15:59:51Z",
"updated_at": "2015-07-16T08:53:32Z",
"mac_address": "[FILTERED]",
"owner": {
"id": 2247,
"uuid": "bcd5b918-d89f-4cb6-a2bb-30245904bc2f",
"username": "JesusZabala",
"avatar": "http://smartcitizen.s3.amazonaws.com/avatars/default.svg",
"url": null,
"joined_at": "2015-02-02T15:55:41Z",
"location": {
"city": null,
"country": null,
"country_code": null
},
"device_ids": [
1616
]
},
"data": {
"recorded_at": "2015-07-16T08:53:32Z",
"added_at": "2015-07-16T08:53:32Z",
"firmware": "[IGNORE]",
"location": {
"ip": null,
"exposure": "outdoor",
"elevation": 1,
"latitude": -8.82111778712582,
"longitude": 115.15258114151,
"geohash": "qw3vu65t38",
"city": "Kuta Selatan",
"country_code": "ID",
"country": "Indonesia"
},
"sensors": [
{
"id": 10,
"ancestry": null,
"name": "Battery",
"description": "Custom Circuit",
"unit": "%",
"created_at": "2015-02-02T18:18:00Z",
"updated_at": "2015-07-05T19:53:51Z",
"measurement_id": 7,
"uuid": "c9ff2784-53a7-4a84-b0fc-90ecc7e313f9",
"value": 100.0,
"raw_value": 1000,
"prev_value": 100.0,
"prev_raw_value": 1000
},
{
"id": 5,
"ancestry": "3",
"name": "DHT22 - Humidity",
"description": "Humidity",
"unit": "%",
"created_at": "2015-02-02T18:15:34Z",
"updated_at": "2015-07-05T19:53:22Z",
"measurement_id": 2,
"uuid": "6b4b64d9-3841-446c-a7f5-63f480932b96",
"value": 1.0,
"raw_value": 10,
"prev_value": 1.0,
"prev_raw_value": 10
},
{
"id": 4,
"ancestry": "3",
"name": "DHT22 - Temperature",
"description": "Temperature",
"unit": "ºC",
"created_at": "2015-02-02T18:15:14Z",
"updated_at": "2015-07-05T19:53:02Z",
"measurement_id": 1,
"uuid": "a50dbd88-b0c7-4094-ad74-2b755e8023a8",
"value": 29.8,
"raw_value": 298,
"prev_value": 29.9,
"prev_raw_value": 299
},
{
"id": 8,
"ancestry": null,
"name": "MICS-2710",
"description": "MOS NO2 gas sensor",
"unit": "kOhm (ppm)",
"created_at": "2015-02-02T18:17:23Z",
"updated_at": "2015-07-05T19:56:21Z",
"measurement_id": 6,
"uuid": "1eb0249d-29d8-41be-8e24-d3b1e5773c0f",
"value": 197.574,
"raw_value": 197574,
"prev_value": 182.971,
"prev_raw_value": 182971
},
{
"id": 9,
"ancestry": null,
"name": "MICS-5525",
"description": "MOS CO gas sensor",
"unit": "kOhm (ppm)",
"created_at": "2015-02-02T18:17:44Z",
"updated_at": "2015-07-05T19:56:07Z",
"measurement_id": 5,
"uuid": "7baaecb7-2586-4063-9c15-bfa999e329aa",
"value": 276.753,
"raw_value": 276753,
"prev_value": 278.468,
"prev_raw_value": 278468
},
{
"id": 21,
"ancestry": null,
"name": "Microchip RN-131",
"description": "802.11 b/g WiFi",
"unit": "# networks",
"created_at": "2015-05-04T11:17:18Z",
"updated_at": "2015-07-05T19:57:22Z",
"measurement_id": 9,
"uuid": "5b1f0e38-336a-4abf-9989-69b48f0026ef",
"value": 4,
"raw_value": null,
"prev_value": 4,
"prev_raw_value": null
},
{
"id": 7,
"ancestry": null,
"name": "POM-3044P-R",
"description": "Electret microphone with envelope follower sound pressure sensor (noise)",
"unit": "dB",
"created_at": "2015-02-02T18:16:41Z",
"updated_at": "2015-07-05T19:56:59Z",
"measurement_id": 4,
"uuid": "5efd2376-6783-476b-bf85-57ead5f89654",
"value": 67.2,
"raw_value": 31,
"prev_value": 59.8,
"prev_raw_value": 13
},
{
"id": 6,
"ancestry": null,
"name": "PVD-P8001",
"description": "LDR Analog Light Sensor",
"unit": "%",
"created_at": "2015-02-02T18:15:55Z",
"updated_at": "2015-07-05T19:56:43Z",
"measurement_id": 3,
"uuid": "0e9cdc5b-d369-4480-9676-bf31af6a5977",
"value": 1.5,
"raw_value": 15,
"prev_value": 1.7,
"prev_raw_value": 17
},
{
"id": 11,
"ancestry": null,
"name": "Solar Panel",
"description": "Custom Circuit",
"unit": "mV",
"created_at": "2015-02-02T18:18:12Z",
"updated_at": "2015-07-05T19:54:09Z",
"measurement_id": 8,
"uuid": "4ab402c5-9297-407a-b0b2-7089520f7ed0",
"value": 5.066,
"raw_value": 5066,
"prev_value": 5.067,
"prev_raw_value": 5067
}
]
},
"kit": {
"id": 2,
"uuid": "1409dba9-b06b-4ea5-904c-e0df6e09b903",
"slug": "sck:1,0",
"name": "SCK 1.0 - Ambient Board",
"description": "Goteo Board",
"created_at": "2015-02-02T18:18:50Z",
"updated_at": "2015-05-25T14:06:25Z"
}
}
Returns a single device. Example of a complete response - http://api.smartcitizen.me/v0/devices/1616
Field | Example | Description |
---|---|---|
id* integer |
1619 | Incremental, unique ID of the device |
uuid* uuid |
"fc9d12cf-b3aa-4030-9abf-2315e8f8a65d" | Unique ID for the device |
name string |
My amazing sensor | Name of the device |
description string |
An SCK in Southwark | Description of the device |
state string |
"has_published" | (Automatic) state of the device. See state. |
system_tags string array |
['new', 'indoor'] | See system_tag values table below. |
user_tags string array |
['new', 'indoor'] | An Array of user tags, predefined from a specific list available in tags. |
last_reading_at* datetime |
"2015-04-30T17:56:04.432Z" | Last reading from any of the sensors of the device. |
created_at* datetime |
"2015-04-30T17:56:04.432Z" | When the device was created in the platform. |
updated_at* datetime |
"2015-04-30T17:56:04.432Z" | When the device info was last updated (it does not get modified by new data). |
notify.stopped_publishing bool |
true | Notification setting in case the device stopped publishing |
notify.low_battery bool |
false | Notification setting in case the device has low battery |
device_token string |
123abc | Device token (secret) |
postprocessing postprocessing |
- | See data postprocessing |
location location |
See location | Object containing device's location |
data_policy policy |
See data policy | Object containing device's data policy |
hardware hardware |
See hardware | Object containing device's hardware information |
owner* owner |
See owner | Device's owner information |
data data |
See data | Data object containing the device's sensors and latest readings |
Location
This object contains information on the device location. Lat/long precision is set to 5 digits (equivalent to a resolution of meters). An optional location blurring feature can be enabled with the precise_location
feature in the data policy field, for those cases that seek to preserve their location privacy (although the device owner place the pin at a different location at their own will). If precise_location
is not enabled, the lat/long precision will still be 5 digits, but the location will be blurred keeping only up to 3 digits of accuracy (hundred meters).
Field | Example | Description |
---|---|---|
location.ip decimal |
||
location.exposure string |
"indoor" | Indoor or Outdoor |
location.elevation decimal |
25 | Elevation of the location where the device is placed |
location.longitude decimal |
-0.08622 | Longitude of the location where the device is placed |
location.latitude decimal |
50.43231 | Latitude of the location where the device is placed |
location.city string |
Southwark | City where the device is located |
location.country_code string |
GB | Alpha-2 Country Code where the device is located |
location.country string |
Great Britain | Country where the device is located |
Data postprocessing
This information is used to process data on those devices that require some automated data processing tools. Check the docs for more information.
Data Policy
This is used to define the user's priority on their device.
Field | Example | Description |
---|---|---|
data_policy.is_private bool |
false | If the device is private or not. This hides the device to other users |
data_policy.enable_forwarding bool |
false | If the device has data forwarding enabled. Currently only available to researchers (see users) |
*data_policy.precise_location * bool |
false | If the device has a precise location enabled. The user can't store a precise location if this is disabled. See location |
Hardware
This object represents the device hardware information.
Field | Example | Description |
---|---|---|
hardware.name string |
"SCK 2.1 with CO2" | Complete name of the device, including hardware definition and version |
hardware.type string |
"SCK" | If the hardware is a SCK or other type |
hardware.version string |
"2.1" | Hardware version, ideally in a major.minor format |
hardware.slug string |
"sck,2.1" | For internal use only |
hardware.last_status_message status |
See status | Status message by the device |
Status
This message is delivered by Smart Citizen devices via MQTT through the info
topic. This is used to retrieve firmware information, and potential debugging information. This is filtered
for unauthorised requests.
Field | Example | Description |
---|---|---|
id string |
AFF32AD50515157382E3120FF152B26 | Serial Number of the main microcontroller |
mac string |
86:0D:8E:A7:4E:7D | MAC address of the Wi-Fi Antenna |
time datetime |
2024-10-03T03:00:18Z | When the last status message was received |
esp_bd datetime |
2024-10-03T03:00:18Z | When the Wi-Fi antenna firmware was built |
hw_ver string |
2.1 | Hardware version |
rcause string |
SYST | Reason for last reset of the device |
sam_bd datetime |
2024-10-03T03:00:18Z | When the main microcontroller firmware was built |
esp_ver string |
0.9.8-48c75ee-master | Wi-Fi antenna firmware version |
sam_ver string |
0.9.8-48c75ee-master | Main microcontroller firmware version |
State
Represents the device state, defined in an automated way by the platform.
Field | Description |
---|---|
not_configured | Device has been added to the platform but we do not have its MAC address |
never_published | Device has been added, we have the MAC but no readings have been received |
has_published | At least one reading has been recorded, submitted and saved to the platform |
archived | The device has been temporarily removed from the platform |
System Tags
String | Description |
---|---|
new | The device was added to the platform less than 7 days ago |
indoor | The device is placed indoors |
outdoor | The device is placed outdoors (default) |
Data
This object contains the latest readings for the device.
Field | Example | Description |
---|---|---|
sensors array of sensors |
[sensor] | An array of sensor objects, with the latest reading value , prev_value , and date of the reading injected into them. It also includes measurement associated with each. |
Add a Device
POST https://api.smartcitizen.me/v0/devices
http POST https://api.smartcitizen.me/v0/devices access_token=9d00b4c027f757ef1c7b254b9f795d1ebd1e04f7a21b01d5a9dfe5f6e37439b5 mac_address='00:0a:95:9d:68:16' name='my sck'
HTTP/1.1 201 Created
{
"added_at": "2015-07-31T10:11:09Z",
"data": {
"added_at": "2015-07-31T10:11:09Z",
"firmware": "[IGNORE]",
"location": {
"city": null,
"country": null,
"country_code": null,
"elevation": null,
"exposure": null,
"geohash": null,
"ip": null,
"latitude": null,
"longitude": null
},
"recorded_at": "2015-07-31T10:11:09Z",
"sensors": []
},
"description": null,
"id": 1816,
"last_reading_at": null,
"mac_address": "00:0a:95:9d:68:16",
"name": "my sck",
"owner": {
"avatar": "http://images.smartcitizen.me/s100/feca2180/firewatch-4.jpg",
"device_ids": [
1816
],
"id": 2997,
"joined_at": "2015-02-02T15:17:28Z",
"location": {
"city": "Barcelona",
"country": "Spain",
"country_code": "ES"
},
"url": null,
"username": "john",
"uuid": "feca2180-d0dd-49fd-8815-ec59ca6d48f6"
},
"state": "never_published",
"system_tags": [
"new",
"offline"
],
"updated_at": "2015-07-31T10:11:09Z",
"uuid": null
}
You must be authenticated to add a device. The currently authenticated user will be registered as the owner
of the new device.
Parameter | Required? | Description |
---|---|---|
name string |
✓ | Name of the device |
description string |
Description of the device | |
exposure string |
Either indoor or outdoor |
|
latitude decimal |
Latitude of the device | |
longitude decimal |
Longitude of the device |
Update a Device
PATCH https://api.smartcitizen.me/v0/devices/:id
http PATCH https://api.smartcitizen.me/v0/devices/1816 access_token=9d00b4c027f757ef1c7b254b9f795d1ebd1e04f7a21b01d5a9dfe5f6e37439b5 description='new description'
HTTP/1.1 200 OK
{
"added_at": "2015-07-31T10:11:09Z",
"data": {
"added_at": "2015-07-31T10:15:06Z",
"firmware": "[IGNORE]",
"location": {
"city": null,
"country": null,
"country_code": null,
"elevation": null,
"exposure": null,
"geohash": null,
"ip": null,
"latitude": null,
"longitude": null
},
"recorded_at": "2015-07-31T10:15:06Z",
"sensors": []
},
"description": "new description",
"id": 1816,
"last_reading_at": null,
"mac_address": "00:0a:95:9d:68:16",
"name": "my sck",
"owner": {
"avatar": "http://images.smartcitizen.me/s100/feca2180/firewatch-4.jpg",
"device_ids": [
1816
],
"id": 2997,
"joined_at": "2015-02-02T15:17:28Z",
"location": {
"city": "Barcelona",
"country": "Spain",
"country_code": "ES"
},
"url": "http://www.google.com",
"username": "john",
"uuid": "feca2180-d0dd-49fd-8815-ec59ca6d48f6"
},
"state": "never_published",
"system_tags": [
"new",
"offline"
],
"updated_at": "2015-07-31T10:15:06Z",
"uuid": "cb480089-c000-4e69-96c0-ad6378f3a537"
}
You must be authenticated and registered as the device's owner
if you wish to update a device.
Parameter | Example | Description |
---|---|---|
id integer |
2 | Unique ID of the device |
name string |
Beach SCK | Name of the device |
description string |
A Smart Citizen on the Beach | Description of the device |
mac_address string |
00:1C:B3:09:85:15 | MAC Address of the device |
user_tags string |
A comma-seperated list of tag names more info | |
exposure string |
Either indoor or outdoor |
|
latitude decimal |
41.401108 | Latitude of the device |
longitude decimal |
2.215319 | Longitude of the device |
Remove a Device
DELETE https://api.smartcitizen.me/v0/devices/:id
http DELETE https://api.smartcitizen.me/v0/devices/10
HTTP/1.1 200 OK
You can only delete devices that you own. After a device is deleted with the API there will be a grace period in which you can contact support to reinstate a device if you have removed it in error. After this grace period has passed, the device and its data will be removed permanently from our databases and cannot be restored.
Get All Devices
GET https://api.smartcitizen.me/v0/devices
http GET https://api.smartcitizen.me/v0/devices
HTTP/1.1 200 OK
[
{
"id": 674,
"uuid": "a31b92f5-0201-4db4-ac9a-3cfb4a8bbe15",
"name": "The Continuum",
"description": "LA CASA",
"state": "never_published",
"system_tags": [
"indoor",
"offline"
],
"last_reading_at": null,
"added_at": "2015-02-02T15:59:48Z",
"updated_at": "2015-05-25T07:31:27Z",
"mac_address": "[FILTERED]",
"owner": {
"id": 498,
"uuid": "4b09f4d3-040d-4b06-b5e3-8dd10b055dea",
"username": "Mike6158",
"avatar": "http://smartcitizen.s3.amazonaws.com/avatars/default.svg",
"url": null,
"joined_at": "2015-02-02T15:55:32Z",
"location": {
"city": null,
"country": null,
"country_code": null
},
"device_ids": [
674
]
},
"data": {
"recorded_at": "2015-05-25T07:31:27Z",
"added_at": "2015-05-25T07:31:27Z",
"firmware": "[IGNORE]",
"location": {
"ip": null,
"exposure": "indoor",
"elevation": 348,
"latitude": 29.7030111,
"longitude": -96.7805333,
"geohash": "9v70vxq8d4",
"city": "Weimar",
"country_code": "US",
"country": "United States"
},
"sensors": [
{
"id": 14,
"ancestry": null,
"name": "BH1730FVC",
"description": "Digital Ambient Light Sensor",
"unit": "Lux",
"created_at": "2015-02-02T18:24:56Z",
"updated_at": "2015-07-05T19:57:36Z",
"measurement_id": 3,
"uuid": "ac4234cf-d2b7-4cfa-8765-9f4477e2de5f",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 17,
"ancestry": null,
"name": "Battery",
"description": "Custom Circuit",
"unit": "%",
"created_at": "2015-02-02T18:26:28Z",
"updated_at": "2015-07-05T19:55:34Z",
"measurement_id": 7,
"uuid": "5b0e390e-781d-4243-8e97-579eead09792",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 13,
"ancestry": "19",
"name": "HPP828E031",
"description": "Humidity",
"unit": "%",
"created_at": "2015-02-02T18:24:30Z",
"updated_at": "2015-07-05T19:54:54Z",
"measurement_id": 2,
"uuid": "1c19ae8f-b995-460f-87a3-a9d0c140abfb",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 12,
"ancestry": "19",
"name": "HPP828E031",
"description": "Temperature",
"unit": "ºC",
"created_at": "2015-02-02T18:24:02Z",
"updated_at": "2015-07-05T19:55:07Z",
"measurement_id": 1,
"uuid": "2922d20e-3b83-4d98-8791-cfcdfc12fa99",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 15,
"ancestry": "20",
"name": "MiCS-4514",
"description": "NO2",
"unit": "kOhm/ppm",
"created_at": "2015-02-02T18:25:51Z",
"updated_at": "2015-07-05T19:57:59Z",
"measurement_id": 6,
"uuid": "0c5b7e74-ef87-431d-89af-dd51de84b10e",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 16,
"ancestry": "20",
"name": "MiCS-4514",
"description": "CO",
"unit": "kOhm/ppm",
"created_at": "2015-02-02T18:26:11Z",
"updated_at": "2015-07-05T19:58:18Z",
"measurement_id": 5,
"uuid": "49a26be4-3ce1-4f2e-a09b-4296fefcfe17",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 21,
"ancestry": null,
"name": "Microchip RN-131",
"description": "802.11 b/g WiFi",
"unit": "# networks",
"created_at": "2015-05-04T11:17:18Z",
"updated_at": "2015-07-05T19:57:22Z",
"measurement_id": 9,
"uuid": "5b1f0e38-336a-4abf-9989-69b48f0026ef",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 7,
"ancestry": null,
"name": "POM-3044P-R",
"description": "Electret microphone with envelope follower sound pressure sensor (noise)",
"unit": "dB",
"created_at": "2015-02-02T18:16:41Z",
"updated_at": "2015-07-05T19:56:59Z",
"measurement_id": 4,
"uuid": "5efd2376-6783-476b-bf85-57ead5f89654",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
},
{
"id": 18,
"ancestry": null,
"name": "Solar Panel",
"description": "Custom Circuit",
"unit": "mV",
"created_at": "2015-02-02T18:26:40Z",
"updated_at": "2015-07-05T19:54:35Z",
"measurement_id": 8,
"uuid": "95d59a95-3791-423c-a201-b19c327765d8",
"value": null,
"raw_value": null,
"prev_value": null,
"prev_raw_value": null
}
]
},
"kit": {
"id": 3,
"uuid": "6ae30424-4e09-4318-b96d-771996657c70",
"slug": "sck:1,1",
"name": "SCK 1.1 - Ambient Board",
"description": "Kickstarter Board",
"created_at": "2015-02-02T18:23:16Z",
"updated_at": "2015-05-25T14:06:46Z"
}
}
...
Returns all devices, with the same data as above.
Parameter | Example | Description |
---|---|---|
near string (lat,lng) |
41.401108, 2.215319 |
When included, returns devices in order of distance from the coordinates |
World Map of Devices
GET https://api.smartcitizen.me/v0/devices/world_map
http GET https://api.smartcitizen.me/v0/devices/world_map
HTTP/1.1 200 OK
[
{
"id": 1630,
"name": "IONIAN UNIVERSITY SMART CITIZEN PROJECT TEST ",
"description": "SMART CITIZEN SENSORS BOARD",
"owner_id": 2278,
"owner_username": "gvlachos",
"latitude": 39.6249838,
"longitude": 19.9223461,
"city": "Kérkira",
"country_code": "GR",
"kit_id": 3,
"state": "has_published",
"system_tags": [
"indoor",
"offline"
],
"exposure": "indoor",
"data": {
"": "2015-06-25T07:45:03Z",
"7": 66.875,
"12": 20.24169189453124,
"13": 70.262939453125,
"14": 290.9,
"15": 20.965,
"16": 558.478,
"17": 100.0,
"18": 4128,
"21": 2,
"7_raw": 255,
"12_raw": 27316,
"13_raw": 33168,
"14_raw": 2909,
"15_raw": 20965,
"16_raw": 558478,
"17_raw": 1000,
"18_raw": 4128
},
"added_at": "2015-02-02T15:59:51Z"
}
...
Returns an array with of summarized device objects for displaying on the world map.
Field | Example | Description |
---|---|---|
id* integer |
1619 | Incremental, unique ID of the device |
name string |
My amazing sensor | Name of the device |
description string |
An SCK in Southwark | Description of the device |
state string |
"has_published" | (Automatic) state of the device. See state. |
system_tags string array |
['new', 'indoor'] | See system_tag values table below. |
user_tags string array |
['new', 'indoor'] | An Array of user tags, predefined from a specific list available in tags. |
last_reading_at* datetime |
"2015-04-30T17:56:04.432Z" | Last reading from any of the sensors of the device. |
location location |
See location | Object containing device's location |
hardware hardware |
See hardware | Object containing device's hardware information |
Sensors
Every device has sensor(s)
. A sensor
is something on a device
that can record data. This could be anything: temperature, noise, humidity, voltage...
Get all Sensors
GET https://api.smartcitizen.me/v0/sensors
http GET https://api.smartcitizen.me/v0/sensors
HTTP/1.1 200 OK
[
{
"id": 3,
"uuid": "ac284ba3-e2fc-4795-b2b1-530b32a9b05b",
"parent_id": null,
"name": "DHT22",
"description": "A digital temperature and humidity sensor. It uses a capacitive humidity sensor and a thermistor to measure the surrounding air, and spits out a digital signal on the data pin (no analog input pins needed)",
"unit": null,
"created_at": "2015-02-02T18:14:15Z",
"updated_at": "2015-02-02T18:14:15Z"
}
...
Since real-world sensors can contain multiple sub-sensors. For instance, the Sensirion SHT31 records temperature and humidity, in a single package. To represent this, we use the concept of parent
. If a sensor
has a parent
then it is a sub-sensor
. You can find which sensor
a sub-sensors
belongs to with the parent_id
.
Parameter | Description |
---|---|
id* integer |
Autoincrementing unique ID for the sensor |
uuid* uuid |
Unique ID for the sensor |
parent_id* integer |
ID of the parent (null if none) |
name string |
Name of the sensor |
description string |
Description of the sensor |
datasheet string |
Link to the sensor datasheet |
unit string |
The unit of measurement for readings recorded with the sensor |
unit_definition string |
Link to the vocabulary for the unit |
measurement measurement |
Measurement taken with the sensor |
tags sensortag |
Sensor tag |
created_at* datetime |
When the sensor was added to the platform |
updated_at* datetime |
When the sensor was updated on the platform |
Get a single Sensor
GET https://api.smartcitizen.me/v0/sensors/:id
http GET https://api.smartcitizen.me/v0/sensors/5
HTTP/1.1 200 OK
{
"id": 5,
"uuid": "6b4b64d9-3841-446c-a7f5-63f480932b96",
"parent_id": 3,
"name": "DHT22 - Humidity",
"description": "Humidity",
"unit": "%",
"created_at": "2015-02-02T18:15:34Z",
"updated_at": "2015-07-05T19:53:22Z",
"measurement": {
"id": 2,
"uuid": "9cbbd396-5bd3-44be-adc0-7ffba778072d",
"name": "relativee humidity",
"description": "Relative humidity is a measure of the amount of moisture in the air relative to the total amount of moisture the air can hold. For instance, if the relative humidity was 50%, then the air is only half saturated with moisture."
}
}
Will return same parameters as above, but for a single sensor.
Readings
Get Latest Readings
GET https://api.smartcitizen.me/v0/devices/:id
http GET https://api.smartcitizen.me/v0/devices/1616
HTTP/1.1 200 OK
{
"id": 1616,
"uuid": "85543ca2-e543-4351-9122-98756d50e6b1",
"name": "Orchid Surf Stay Bali",
"description": "Located at the pool area of the hotel ",
"state": "has_published",
"system_tags": [
"offline",
"outdoor"
],
"last_reading_at": "2015-07-16T08:53:16Z",
"added_at": "2015-02-02T15:59:51Z",
"updated_at": "2015-07-16T08:53:32Z",
"mac_address": "[FILTERED]",
"owner": {
"id": 2247,
"uuid": "bcd5b918-d89f-4cb6-a2bb-30245904bc2f",
"username": "JesusZabala",
"avatar": "http://smartcitizen.s3.amazonaws.com/avatars/default.svg",
"url": null,
"joined_at": "2015-02-02T15:55:41Z",
"location": {
"city": null,
"country": null,
"country_code": null
},
"device_ids": [
1616
]
},
"data": {
"recorded_at": "2015-07-16T08:53:32Z",
"added_at": "2015-07-16T08:53:32Z",
"firmware": "[IGNORE]",
"location": {
"ip": null,
"exposure": "outdoor",
"elevation": 1,
"latitude": -8.82111778712582,
"longitude": 115.15258114151,
"geohash": "qw3vu65t38",
"city": "Kuta Selatan",
"country_code": "ID",
"country": "Indonesia"
},
"sensors": [
{
"id": 10,
"ancestry": null,
"name": "Battery",
"description": "Custom Circuit",
"unit": "%",
"created_at": "2015-02-02T18:18:00Z",
"updated_at": "2015-07-05T19:53:51Z",
"measurement_id": 7,
"uuid": "c9ff2784-53a7-4a84-b0fc-90ecc7e313f9",
"value": 100.0,
"raw_value": 1000,
"prev_value": 100.0,
"prev_raw_value": 1000
},
{
"id": 5,
"ancestry": "3",
"name": "DHT22 - Humidity",
"description": "Humidity",
"unit": "%",
"created_at": "2015-02-02T18:15:34Z",
"updated_at": "2015-07-05T19:53:22Z",
"measurement_id": 2,
"uuid": "6b4b64d9-3841-446c-a7f5-63f480932b96",
"value": 1.0,
"raw_value": 10,
"prev_value": 1.0,
"prev_raw_value": 10
},
{
"id": 4,
"ancestry": "3",
"name": "DHT22 - Temperature",
"description": "Temperature",
"unit": "ºC",
"created_at": "2015-02-02T18:15:14Z",
"updated_at": "2015-07-05T19:53:02Z",
"measurement_id": 1,
"uuid": "a50dbd88-b0c7-4094-ad74-2b755e8023a8",
"value": 29.8,
"raw_value": 298,
"prev_value": 29.9,
"prev_raw_value": 299
},
{
"id": 8,
"ancestry": null,
"name": "MICS-2710",
"description": "MOS NO2 gas sensor",
"unit": "kOhm (ppm)",
"created_at": "2015-02-02T18:17:23Z",
"updated_at": "2015-07-05T19:56:21Z",
"measurement_id": 6,
"uuid": "1eb0249d-29d8-41be-8e24-d3b1e5773c0f",
"value": 197.574,
"raw_value": 197574,
"prev_value": 182.971,
"prev_raw_value": 182971
},
{
"id": 9,
"ancestry": null,
"name": "MICS-5525",
"description": "MOS CO gas sensor",
"unit": "kOhm (ppm)",
"created_at": "2015-02-02T18:17:44Z",
"updated_at": "2015-07-05T19:56:07Z",
"measurement_id": 5,
"uuid": "7baaecb7-2586-4063-9c15-bfa999e329aa",
"value": 276.753,
"raw_value": 276753,
"prev_value": 278.468,
"prev_raw_value": 278468
},
{
"id": 21,
"ancestry": null,
"name": "Microchip RN-131",
"description": "802.11 b/g WiFi",
"unit": "# networks",
"created_at": "2015-05-04T11:17:18Z",
"updated_at": "2015-07-05T19:57:22Z",
"measurement_id": 9,
"uuid": "5b1f0e38-336a-4abf-9989-69b48f0026ef",
"value": 4,
"raw_value": null,
"prev_value": 4,
"prev_raw_value": null
},
{
"id": 7,
"ancestry": null,
"name": "POM-3044P-R",
"description": "Electret microphone with envelope follower sound pressure sensor (noise)",
"unit": "dB",
"created_at": "2015-02-02T18:16:41Z",
"updated_at": "2015-07-05T19:56:59Z",
"measurement_id": 4,
"uuid": "5efd2376-6783-476b-bf85-57ead5f89654",
"value": 67.2,
"raw_value": 31,
"prev_value": 59.8,
"prev_raw_value": 13
},
{
"id": 6,
"ancestry": null,
"name": "PVD-P8001",
"description": "LDR Analog Light Sensor",
"unit": "%",
"created_at": "2015-02-02T18:15:55Z",
"updated_at": "2015-07-05T19:56:43Z",
"measurement_id": 3,
"uuid": "0e9cdc5b-d369-4480-9676-bf31af6a5977",
"value": 1.5,
"raw_value": 15,
"prev_value": 1.7,
"prev_raw_value": 17
},
{
"id": 11,
"ancestry": null,
"name": "Solar Panel",
"description": "Custom Circuit",
"unit": "mV",
"created_at": "2015-02-02T18:18:12Z",
"updated_at": "2015-07-05T19:54:09Z",
"measurement_id": 8,
"uuid": "4ab402c5-9297-407a-b0b2-7089520f7ed0",
"value": 5.066,
"raw_value": 5066,
"prev_value": 5.067,
"prev_raw_value": 5067
}
]
},
"kit": {
"id": 2,
"uuid": "1409dba9-b06b-4ea5-904c-e0df6e09b903",
"slug": "sck:1,0",
"name": "SCK 1.0 - Ambient Board",
"description": "Goteo Board",
"created_at": "2015-02-02T18:18:50Z",
"updated_at": "2015-05-25T14:06:25Z"
}
}
(for a device)
The latest set of readings is included with the device, so if you call /v0/devices/:id
you will see the most recent set of readings embedded in data.sensors
as value
and raw_value
.
Get Historical Readings
GET https://api.smartcitizen.me/v0/devices/:device_id/readings
http GET https://api.smartcitizen.me/v0/devices/1616/readings?sensor_id=7&rollup=4h&from=2015-07-28&to=2015-07-30
HTTP/1.1 200 OK
{
"device_id": 1616,
"sensor_id": 7,
"rollup": "4h",
"function": "avg",
"from": "2015-07-28T00:00:00Z",
"to": "2015-07-30T00:00:00Z",
"sample_size": 1776,
"readings": [
[
"2015-07-29T20:00:35Z",
65.78151658767773
],
[
"2015-07-29T16:00:46Z",
65.67438423645321
],
[
"2015-07-29T12:00:06Z",
65.88564593301437
],
[
"2015-07-29T08:00:07Z",
65.86494845360832
],
[
"2015-07-29T04:00:36Z",
65.47640791476408
],
[
"2015-07-29T00:00:12Z",
64.98706140350879
],
[
"2015-07-28T20:00:38Z",
63.82850241545894
],
[
"2015-07-28T16:00:03Z",
65.36859903381644
],
[
"2015-07-28T14:14:05Z",
65.28877551020409
]
]
}
Returns the readings that were recorded for a specific sensor on a device.
Readings are returned as a tuple [recorded_at
, value
]
Request Parameters
Parameter | Example | Required? | Description |
---|---|---|---|
device_id integer |
2 | ✓ | Unique ID of the device |
sensor_id integer |
7 | ✓ | Unique ID of the sensor on the device |
rollup string |
1w (1 week) | ✓ | Timespan to use when grouping readings. See table |
from datetime |
2015-07-20 00:00:00 UTC | The start of the range of readings | |
to datetime |
2015-07-27 00:00:00 UTC | The end of the range of readings | |
function string |
avg | Method to use when grouping the readings. See table | |
all_intervals boolean |
true | Include all possible timestamps within the from > to range, even if they have nil values |
Response
Field | Description |
---|---|
device_id integer |
Unique ID of the device |
rollup string |
Timespan of data groups |
function string |
How the readings collection should be grouped |
from datetime |
The beginning of the timeframe |
from datetime |
The end of the timeframe |
sample_size integer |
The count of readings that were examined to build the response |
readings array |
Array of tuples, representing the recorded_at and value of each reading |
Rollup measurements
key | value |
---|---|
y | years |
M | months |
w | weeks |
d | days |
h | hours |
m | minutes |
s | seconds |
ms | milliseconds |
Functions
Parameter | Description |
---|---|
avg | Computes average readings within the rollup period |
max | Returns the largest readings within the rollup period |
min | Returns the smallest readings within the rollup period |
sum | Sums all readings within the rollup period |
count | Counts the number of readings within rollup periods |
dev | Computes standard deviation |
first | Returns the first readings within the rollup period |
last | Returns the last readings within the rollup period |
CSV Archive of readings
GET https://api.smartcitizen.me/v0/devices/:id/readings/csv_archive
access_token
authentication required, you must either be the owner of the device or an admin.
possible responses:
Error Code | Meaning |
---|---|
200 |
OK, job has been enqueued and the user will be emailed a link to the CSV file |
401 |
Unauthorised |
403 |
Forbidden |
404 |
Device not found |
420 |
(rate limiting, please only make one request every X -- currently X = 6 hours) |
500 |
Server Error |
If you try to GET the endpoint multiple times you will receive a 420
rate limit error until 6 hours have passed.
Post Readings
A device has one Blueprint we call kit
, and a blueprint has many sensors
through components
.
Most devices on the platform share the same blueprint, a default SCK 1.1 (e.g. Kickstarter Board). But new devices (e.g. Raspberry Pi's, new Sensor Add-ons) might use a different Blueprints.
GET https://api.smartcitizen.me/v0/devices/:device_id/readings
access_token
authentication required, you must either be the owner of the device or an admin.
http POST https://api.smartcitizen.me/v0/devices/1816/readings?access_token=xxxxxxxxxxx
{
"data": [{
"recorded_at": "2016-06-08 10:30:00",
"sensors": [{
"id": 22,
"value": 21
}]
}]
}
{
"data": [{
"recorded_at": "2016-06-08 10:30:00",
"sensors": [{
"id": "temp",
"value": 21
}]
}]
}
Request Parameters
Parameter | Example | Required? | Description |
---|---|---|---|
data array |
✓ | The data payload |
Data Parameters
Parameter | Example | Required? | Description |
---|---|---|---|
recorded_at datetime |
2015-07-20 00:00:00 UTC | ✓ | The time when the reading took place |
sensors array |
✓ | The sensors objects |
Sensor Parameters
Parameter | Example | Required? | Description |
---|---|---|---|
id integer |
12 | ✓ | The id |
id string |
temp | Instead of the id we can use a hash as defined on the Blueprint | |
value float |
22 | ✓ | The value of the sensor (can be an integer or float) |
Measurements
Measurements help us understand what Sensors are recording.
Get All Measurements
GET https://api.smartcitizen.me/v0/measurements
http GET https://api.smartcitizen.me/v0/measurements
HTTP/1.1 200 OK
[
{
"id": 1,
"uuid": "b3f44b63-0a17-4d84-bbf1-4c17764b7eae",
"name": "air temperature",
"description": "Air temperature is a measure of how hot or cold the air is. It is the most commonly measured weather parameter. Air temperature is dependent on the amount and strength of the sunlight hitting the earth, and atmospheric conditions, such as cloud cover and humidity, which trap heat.",
"created_at": "2015-07-03T10:16:10Z",
"updated_at": "2015-07-03T10:16:10Z"
}
...
Parameter | Description |
---|---|
id* integer |
Autoincrementing unique ID for the measurement |
uuid* uuid |
Unique ID for the measurement |
name string |
Name of the measurement |
description string |
Description of the measurement |
definition string |
Link to a vocabulary defining the measurement |
created_at* datetime |
When the measurement was added to the platform |
updated_at* datetime |
When the measurement was updated on the platform |
Get a single Measurement
GET https://api.smartcitizen.me/v0/measurements/:id
GET https://api.smartcitizen.me/v0/measurements/2
HTTP/1.1 200 OK
{
"id": 2,
"uuid": "9cbbd396-5bd3-44be-adc0-7ffba778072d",
"name": "relativee humidity",
"description": "Relative humidity is a measure of the amount of moisture in the air relative to the total amount of moisture the air can hold. For instance, if the relative humidity was 50%, then the air is only half saturated with moisture.",
"created_at": "2015-07-03T10:16:23Z",
"updated_at": "2015-07-03T10:16:23Z"
}
Components
Components
are used to join Devices to Sensors. These are not accessible via the API, but are documented here for reference in case you deploy the platform yourself.
Field | Description |
---|---|
id* integer |
Autoincrementing unique ID for the component |
uuid* uuid |
Unique ID for the component |
device_id* integer |
ID of the Device that the component is associated with |
sensor_id* integer |
ID of the Sensor that the component is associated with |
created_at* datetime |
When the component was added to the platform |
updated_at* datetime |
When the component was updated on the platform |
Experiments
Experiments are collection of devices that represent a real-world-experiment by a user or group of users. This is currently a experimental feature.
Get an experiment
GET https://api.smartcitizen.me/v0/experiment/:id
Returns a single experiment.
Field | Example | Description |
---|---|---|
id* integer |
1 | Incremental, unique ID of the experiment |
name string |
My experiment | Name of the experiment |
description string |
Deployment of sensors | Description of the deviexperimentce |
owner_id* int |
See owner | Experiment's owner ID |
active* bool |
True | If the experiment is active or not, derived from starts_at and ends_at |
starts_at* datetime |
"2015-04-30T17:56:04.432Z" | When the experiment started. |
ends_at* datetime |
"2015-04-30T17:56:04.432Z" | When the experiment finished. |
device_ids* Array |
[19, 149, 2902] | Array of devices IDs |
created_at* datetime |
"2015-04-30T17:56:04.432Z" | When the experiment was created in the platform. |
updated_at* datetime |
"2015-04-30T17:56:04.432Z" | When the experiment info was last updated. |
Add an Experiment
POST https://api.smartcitizen.me/v0/experiment
You must be authenticated to add an experiment. The currently authenticated user will be registered as the owner
of the new experiment.
Parameter | Required? | Description |
---|---|---|
name string |
✓ | Name of the experiment |
description string |
Description of the experiment. | |
starts_at* datetime |
When the experiment started. | |
ends_at* datetime |
When the experiment finished. | |
device_ids* Array |
Array of devices IDs. Not necessarily owned by the owner of the experiment. |
Update an experiment
PATCH https://api.smartcitizen.me/v0/experiment/:id
You must be authenticated and registered as the experiment's owner
if you wish to update an experiment. See Add an experiment.
Remove an experiment
DELETE https://api.smartcitizen.me/v0/experiment/:id
You can only delete experiments that you own. Deleting an experiment, doesn't delete the devices associated with them.
Get All Experiments
GET https://api.smartcitizen.me/v0/experiments
Returns all experiments, with the same data as above.
Tags
Tags are used on devices to group them in flexible ways.
Get all Tags
GET https://api.smartcitizen.me/v0/tags
GET https://api.smartcitizen.me/v0/tags
HTTP/1.1 200 OK
[
{
"id": 1,
"uuid": "f7f09e83-9da9-431b-9be2-cc411f40afbf",
"name": "testtag",
"description": "test description"
}
...
Parameter | Example | Description |
---|---|---|
id integer |
2 | Unique ID of the tag |
name string |
example-tag | Unique name of the tag [A-Za-z0-9-_] |
description string |
Further information about the tag | |
created_at* datetime |
When the tag was added to the platform | |
updated_at* datetime |
When the tag was updated on the platform |
Adding/editing a device's tags
PATCH https://api.smartcitizen.me/v0/devices/:id
Include comma seperated list of tag names in user_tags
property.
For example, if there are tags with the names interesting
and cool-hardware
you could add these tags to a device by PATCHING user_tags = 'interesting,cool-hardware'
.
If you then wanted to remove cool-hardware you would PATCH again, but without the second tag i.e. user_tags = interesting
.
Creating a Tag
POST https://api.smartcitizen.me/v0/tags
Admin only
Updating a Tag
PATCH https://api.smartcitizen.me/v0/tags/:id
Admin only
Deleting a Tag
DELETE https://api.smartcitizen.me/v0/tags/:id
Admin only
Sensor Tags
Sensor tags are not available via the API. This documentation is included only for reference.
Sometimes, it's useful to associate tags to sensors, to make it easier to understand what the are. For instance, a Carbon monoxide sensor may record voltages, and we may want to consider those readings as raw. This is represented with SensorTags. However, since voltage can be also used for measuring electric properties, we use these tags, and not other ad-hoc measurements to avoid duplication.
Response Status Codes
Error Messages
HTTP/1.1 404 Not Found
{
"id" : "record_not_found",
"message" : "Couldn't find Device with 'id'=101308",
"errors": null,
"url" : null
}
HTTP/1.1 422 Unprocessable Entity
{
"id": "unprocessable_entity",
"message": "Unprocessable Entity",
"errors": {
"mac_address": [
"can't be blank",
"is invalid"
],
"name": [
"can't be blank"
]
},
"url": null
}
When possible, read the HTTP status codes to learn of the success of your request. The API uses the following pattern for error messages, as recommended by https://github.com/interagent/http-api-design.
Success Codes
Code | Meaning |
---|---|
200 | Request succeeded for a GET call, for a DELETE or PATCH call that completed synchronously, or for a PATCH call that synchronously updated an existing resource |
201 | Request succeeded for a POST call that completed synchronously, or for a PATCH call that synchronously created a new resource |
Error Codes
Code | Meaning |
---|---|
400 | Bad Request -- there is a problem with your request |
401 | Unauthorized -- Your authentication credentials are incorrect |
403 | Forbidden -- The resource requested is hidden, or you do not have the necessary privileges |
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 |
422 | Unprocessable Entity: Your request was understood, but contained invalid parameters |
429 | Too Many Requests |
500 | Internal Server Error |
503 | Service Unavailable -- We're temporarially offline for maintanance. Please try again later |
Real Time
Websockets
The real time API uses websockets to push devices information in real-time and it is based on the famous socket.io library. We support WSS, WebSockets over SSL/TLS, like HTTPS. We also support fallback to long polling for older browsers.
data-received
is currently the only available topic. Everytime a device publishes data to the platform data is pushed over the channel. With the same model as device GET
.
#See the javascript section
io.connect('wss://ws.smartcitizen.me').on('data-received', doSomething);
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.6/socket.io.js"></script>
<style>
body {
font-family: Helvetica, Arial, sans-serif;
color: white;
font-weight: bold;
}
div {
float: left;
display: block;
background: #4FC9E8!important;
margin: 5px;
width: 100px;
padding: 5px;
height: 100px;
}
</style>
<script>
io.connect('wss://ws.smartcitizen.me')
.on('data-received',
function(device) {
document.body.innerHTML = document.body.innerHTML
+ "<div>" + device.data.name + "</div>"
});
</script>
</head>
<body>
</body>
</html>
Live demo: http://codepen.io/pral2a/pen/jrPNzy
Data forwarding
MQTT
Instead of using websockets, you can also use MQTT, to get rendered data from the devices in real-time. This can help into bringing MQTT features such as persistent sessions and allow for a more robust data ingestion. We support MQTT/s, MQTT over SSL/TLS, like HTTPS. Everytime a device publishes data to the platform data is pushed over, with the same model as device GET
.
MQTT forwarding is only enabled if the user is a researcher
(see users) and if they have enabled forwarding on their device. See data policy on the device section. You need to collect your forwarding_username
and forwarding_token
secrets from the users endpoint after an authenticated request.
# You will need mosquitto (and mosquitto_sub) for this
mosquitto_sub -h mqtt.smartcitizen.me -u '<forwarding_username>' -t '/forward/<forwarding_token>/device/<device_id>/readings' -v
# You can get all the devices from a user
mosquitto_sub -h mqtt.smartcitizen.me -u '<forwarding_username>' -t '/forward/<forwarding_token>/device/+/readings' -v
# Note that wildcard topics at the /forward level are not allowed
Onboarding
Start onboarding process
POST https://api.smartcitizen.me/v0/onboarding/device
http POST https://api.smartcitizen.me/v0/onboarding/device
HTTP/1.1 200 OK
[
{
"onboarding_session": "a562f6bb-4328-4d5b-bb9f-ea6bd8e592a8",
"device_token": "d803e0"
}
...
Method creates orphan_device
and returns unique onboarding_session
and device_token
.
Requires no params at all, however, it can take any of the following: name
, description
, kit_id
, exposure
, latitude
, longitude
, user_tags
.
Any passed params will be used on the creation of the orphan_device
.
Note that both device_token
and onboarding_session
are unique for each orphan_device
.
Parameter | Description |
---|---|
name string |
Name of the device |
description string |
Description of the device |
kit_id integer |
Unique ID of the kit for the device |
exposure string |
Either indoor or outdoor |
latitude decimal |
Latitude of the device |
longitude decimal |
Longitude of the device |
user_tags string |
A comma-seperated list of tag names more info |
Update orphan_device
PATCH https://api.smartcitizen.me/v0/onboarding/device
Method to update (slide by slide, or all at once) the still 'orphan' device. It requires a valid 'Onboarding-Session' header and returns updated 'orphan_device' (status 200) if successfully updated.
Calling without an existent 'Onboarding-Session' returns error "Invalid onboarding_session" (404).
#bash
curl -XPATCH 'https://api.smartcitizen.me/v0/onboarding/device' -H "OnboardingSession: d049c9e7-0261-49e4-91be-8a0bafa1c8b9"
Find existing user
POST https://api.smartcitizen.me/v0/onboarding/user
Method that requires params 'email' and returns user 'username' if email is associated to an existent user (status 200). If 'email' does not correspond to any user (404) not_found
is returned.
Calling without 'email' params results in a 422, "Missing Params".
#bash
curl -XPOST 'https://api.smartcitizen.me/v0/onboarding/user?email=user1@test.com'
# Post:
{
"email": "user1@email.com"
}
# Response:
{
"username": "user1"
}
User login
In order to complete the 'Onboarding Process', it is required user authentication.
Register device
POST https://api.smartcitizen.me/v0/onboarding/register
Method adds to the current_user
a new device
using onboarding_session's correspondent orphan_device
attributes.
- It returns newly created
device
. - If 'Onboarding-Session' is not valid, (404) "Invalid onboarding_session".
- Requires user authentication, otherwise (401) "Authorization required" is returned.
- Requires all the
/onboarding/device
parameters to be provided (name, description, kit_id, exposure, latitude, longitude, user_tags
), otherwise results in a 422, "Missing Params".
#bash
curl -XPOST 'https://api.smartcitizen.me/v0/onboarding/register?access_token=abcdefghijk' -H "OnboardingSession: d049c9e7-0261-49e4-91be-8a0bafa1c8b9"
{
"id": 1,
"owner_id": 2,
"name": "OrphanDeviceName",
"description": "OrphanDeviceDescription",
"mac_address": nil,
"latitude": 41.3966908,
"longitude": 2.1921909,
"created_at": "2016-10-29T12:31:25+02:00",
"updated_at": "2016-10-29T12:31:25+02:00",
"kit_id": 1,
"latest_data": nil,
"geohash": "sp3e9bh31y",
"last_recorded_at": nil,
"meta": {
"exposure": "indoor"
},
"location": {
"address": "Carrer de Pallars, 122, 08018 Barcelona, Barcelona, Spain",
"city": "Barcelona",
"postal_code": "08018",
"state_name": "Catalunya",
"state_code": "CT",
"country_code": "ES"
},
"data": nil,
"old_data": nil,
"owner_username": "user2",
"uuid": nil,
"migration_data": nil,
"workflow_state": "active",
"csv_export_requested_at": nil,
"old_mac_address": nil,
"state": "not_configured"
}
This is the end of the onboarding process.