Beddit Pro API v2

2013-03-07

- Added sleep time goals to user resource (section 5.2.1)

- Support updating user information with PUT request (section 5.2.2)

2013-03-05

- Added some Beddit Lab organization resources (section 5.10)

- Added description of used HTTP verbs (section 2)

- Support assigning and removing device for user (section 5.3)

2012-06-06

- Added resource for getting the sleep analysis state and for requesting re-analysis

2012-04-20

- Added documentation about error responses and messages

- Added resources for getting signal and results by time interaval

2012-04-12

- Added streaming resource

2012-04-11

- Added BCG signal resource

2012-03-23

- Changed binary actigram in results resource to flat list

- Added chapter about Beddit algorithm architecture

2012-03-16

Initial version

1. Introduction

An API is a thing that lets developers create applications that access the information in Beddit.com in machine-understandable form. You can create your own mobile, desktop, or web applications that use the sleep data in Beddit.com service. To keep up with the development of Beddit, please follow us in Twitter @beddit and read blog at http://blog.beddit.com!

1.1 Terms of use

The Beddit API is free to use for non-commercial applications. If you would like to use the API for commercial purposes, please contact us at hello@beddit.com.

1.2 Registering your application

To use the Beddit API with OAuth2 authentication, you need to register your application with us. Once you have registered your application, you will get a client_id and client_secret.

For now, you can register your application by emailing us at hello@beddit.com. We need the following information:

The name, description, and the home page link are shown to the users which are using the application.

1.3 Changes from initial API version 1

2. General

Currently most of the resources support only reading the data with HTTP GET method. Some resources, however, also support changing the data. The following table contains examples of how different HTTP verbs are used.

Example resource

HTTP verb

Meaning

/api2/user/

GET

Retrieve a list of organizations

/api2/user/<username>

GET

Retrieve the given organization’s information

/api2/user/<username>

PUT

Update existing resource’s information

/api2/user/<username>/device

POST

Add a new resource, i.e. a device for the user

/api2/user/<username>/device

DELETE

Remove the resource, i.e. the device from the user

Unless otherwise noted, all data is returned in application/json format. If you try the url:s with a web browser, it might offer you to save the file instead of showing the raw json data. For testing and debugging, you may append mimetype=text/plain parameter to your request. That way, your browser should display the data directly.

All url:s start with https://api.beddit.com/api2/ and require the use of HTTPS.

3. OAuth2 authentication

Beddit API requests are authenticated with OAuth2 protocol. The user must first grant your application access to her data. Once the user has granted the permission, you receive an access code that you can use retrieve an access token.

The access token is used instead of username and password combination in all API requests.

3.1 Obtaining authorization code

Redirect the user to https://api.beddit.com/api/oauth/authorize with your client_id and the URL the user should be redirected back to after the authorization process (redirect_uri):

https://api.beddit.com/api/oauth/authorize?

   client_id=...&

   redirect_uri=http://www.example.com/oauth_redirect&

   response_type=code

3.2 Obtaining access token

If the user authorizes your application, we redirect the user back to the redirect URI you specified with a verification string in the argument code, which can be exchanged for an OAuth access token. Exchange it for an access token by fetching https://api.beddit.com/api/oauth/access_token. Pass the exact same redirect_uri as in the previous step:

https://api.beddit.com/api/oauth/access_token?

   client_id=...&

   redirect_uri=http://www.example.com/oauth_redirect&

   client_secret=...&

   grant_type=code&

   code=...

If all goes well, you will receive a response with the access token in application/json format:

{

 "access_token": "..."

}

3.3 Making API requests

Use the access token returned by the request above to make requests on behalf of the user:

https://api.beddit.com/api2/user?access_token=...

4. About Beddit architecture

To understand what data is available from Beddit, you need to know something about the Beddit signal processing architecture.

The vital sign and sleep measurement are based on ballistocardiography (BCG), the measurement of forces caused by heart beating. The Beddit sensor is completely passive. In the bed, it measures the small vibrations caused by persons movement, heart beat, and respiration. In addition, the device measures some environmental data: room temperature, noise level and ambient light (luminosity).

All the vital sign and sleep information is computed at the server side. The device only records dynamic force signal (the raw BCG signal) and uploads it to the servers. The uploading is done in small chunks, in almost real-time. On the server, there are two kinds of algorithms that process the data. First, real-time algorithms are used to compute persons presence information, heart beat, respiration, and binary actigram (actigraphy in zero-crossing mode). These data are usually computed and available within minutes. Secondly, there are sleep stage computing algorithms, which use the data from whole night. Because the sleep algorithms use data from the whole night, they are run periodically (currently about once an hour).

Thus, the vital sign and sleep data is available in two separate resources (see chapters 5.5 and 5.6). For real-time access to latest data Beddit offers streaming resources (see chapter 6).

5. Resources

5.1 /api2/user

Lists all users which the currently authenticated user can access

Example:

[

    {

        "username": "mikko",

        "url": "https://api.beddit.com/api2/user/mikko", // More info

        "first_name": "Mikko",

        "last_name": "Waris",

        "email": "mikko@beddit.com"

    },

    … // Additional users which the authenticated user has access to

]

5.2 /api2/user/<username>

5.2.1 GET method

Get more information about the user

Example response:

{

    "username": "mikko",

    "first_name": "Mikko",

    "last_name": "Waris",

    "weight": null,

    "language": "en",

    "gender": "-",

    "height": 167.0,

    "night_start_time": "21:00:00", // Start time of measurement

    "night_end_time": "10:00:00",   // End time of measurement

    "device_url": "https://api.beddit.com/api2/user/mikko/device",

    "date_of_birth": "1981-03-05",

    "timezone": "Europe/Helsinki",

    "email": "mikko@beddit.com",

    "device_port": 1 // The port into which the sensor is connected to

    // Sleep goals fields:

    "time_sleeping_min" : 25200, // Minimum time sleeping, in seconds

    "time_deep_sleep_min" : 3600, // Minimum deep sleep time

    "time_rem_sleep_min" : 3600, // Minimum rem sleep time

    "sleep_efficiency_min" : 85, // Minimum sleep efficiency, in percent

   

}

5.2.2 PUT method

Update user’s information. You can include only the fields that you want to update, others are left as they were.

The following data formats are supported. You need to specify the correct data format in CONTENT_TYPE header.

Note that changing device port is not supported (see section 5.3 for changing the device).

Returns the same response as the GET method.

5.3 /api2/user/<username>/device

Get information about the device and it’s current status, or and assign or remove the device from the user.

5.3.1 GET method

Example response:

{

    "name": "ba-0019f4ec0080",

    "secret": "xxxx-xxxx-xxxx-xxxx", // The device key code

    "software_version": "trunk-r7773/trunk-r7564",

    "local_ip": "192.168.100.100",

    "networking_mode": "wlan", // Or “ethernet” or “no_network”

    "last_update": "2012-03-15T22:32:50", // Last contact with server

    "queue_size": 0, // # of ~15sec packets of data buffered on the device

    "local_time": "2012-03-15T22:32:50",

    "is_update_delayed": false, // Is the last_update time unusually old

    "global_ip": "<hidden>",

    "users": [

        {

            "username": "eva",

            "url": "https://api.beddit.com/api2/user/eva",

            "first_name": "Eva",

            "last_name": "Ahl-Waris",

            "email": "<hidden>"

        },

        {

            "username": "mikko",

            "url": "https://api.beddit.com/api2/user/mikko",

            "first_name": "Mikko",

            "last_name": "Waris",

            "email": "mikko@beddit.com"

        }

    ]

}

POST method

The HTTP POST method can be used to assign a device for the user. If the user already has another device assigned, it is first removed.

Parameter

Required

Value

secret

Yes

The key code found in the bottom of the device.

device_port

Yes

Which sensor port of the device to use. Possible values are 1 and 2.

DELETE method

Remove a device from the user. The data measured with the device is no longer associated to the user.

5.4 /api2/user/<username>/timeline?start=YYYY-MM-DD&end=YYYY-MM-DD

Get overview information from range of nights

Note that these are in no particular order

Example:

[

    {

        "local_start_time": "2012-03-11T21:00:00",

        "local_end_time": "2012-03-12T10:00:00",

        "local_analyzed_up_to_time": "2012-03-12T09:59:57",

        "timezone": "Europe/Helsinki", 

        "date": "2012-03-12",

        "url": "https://api.beddit.com/api2/user/mikko/2012/3/12/sleep",

        "is_analysis_up_to_date": true,

        "analysis_complete": true,

        "analysis_valid": true,

        "resting_heartrate": 53.0973451325, // Beats per minute

        "time_light_sleep": 21804, // Seconds

        "time_sleeping": 35860,

        "stress_percent": 52, // 0-100%

        "time_in_bed": 37492,

        "sleep_efficiency": 95.6470713752, // 0-100%

        "time_deep_sleep": 14056

    },

    … # Rest of the nights

]

5.5 /api2/user/<username>/<year>/<month>/<day>/sleep

Get detailed information about one night.

These data are updated about once an hour during the night. Some data, however are updated more frequently, see the following results resource.

Example of sleep data:

{

    "date": "2012-03-14",

    "timezone": "Europe/Helsinki",

    "local_start_time": "2012-03-13T21:00:00",

    "local_end_time": "2012-03-14T10:00:00",

    "local_analyzed_up_to_time": "2012-03-14T09:59:52",

    "is_analysis_up_to_date": true, // Analysis is not lagging real-time

    // There will be no more changes for this nights sleep information

    "analysis_complete": true,

    // If this is false, sleep result fields are not included in response:

    "analysis_valid": true,

    "stress_percent": 73,

    "time_in_bed": 32292, // These summary times are seconds

    "time_light_sleep": 21064,

    "time_sleeping": 31406,

    "time_deep_sleep": 10342,

    "sleep_efficiency": 97.2562863867, // Percent of time in bed slept

    "resting_heartrate": 53.2544378696,

    "minutely_actigram": [

        0,

        2,

        …

        // Rest of the actigram. An integer value for each minute

        // between the night start time and night end time. Basically,

        // it’s the number of movements occurred.

     ]

    "noise_measurements": [

        [

            [

                "2012-03-13T21:00:10",

                43.0 // Maximum noise value in dB

            ],

            … // Array of arrays of noise measurements

         ]

     ],

    "luminosity_measurements": [

        [

            [

                "2012-03-13T21:00:10",

                0.0

            ],

            … // Rest of the luminosity measurements in Lux

        ]

     ],

    "sleep_stages": [

        [

            "2012-03-13T21:00:00",

            "A" // Away

        ],

        [

            "2012-03-13T23:17:00",

            "W" // Wake

        ],

        [

            "2012-03-13T23:25:06",

            "L" // Light sleep

        ],

        [

            "2012-03-13T23:56:00",

            "D" // Deep sleep

        ],

        [

            "2012-03-13T23:58:00",

            "M" // Data is missing

        ],

        … // Rest of the sleep stages

}

In averaged_heart_rate_curve and environment measurements, lists of lists are used so that it is possible to represent gaps in measurements.

5.6 /api2/user/<username>/<year>/<month>/<day>/sleep/queue_for_analysis

HTTP Method

Description

GET

Get the processing status of the sleep information

POST

Request analysis of the sleep information

Normally, sleep data are analyzed periodically and when all data from the night has been collected.


If you need to get up-to-date sleep information at any point of the night, you can check this resource to see if there is new data available and if the sleep can be re-prosessed at this time.

Example data returned:

{

    "results_available_up_to": "2012-06-08T09:59:47",

    "sleep_analysis_status": "analysis_up_to_date",

    "results_available_up_to_when_sleep_analyzed": "2012-06-08T09:59:47",

    "results_available_up_to_when_queued_for_sleep_analysis": null

}

The sleep_analysis_status may be one of:

If the state is can_be_queued_for_analysis, you can send a POST request to this resource. The sleep is then scheduled for re-analysis.

5.7 /api2/user/<username>/<year>/<month>/<day>/results

Get detailed vital sign analysis results from one night.

This resource is updated more frequently than the sleep resource.

NOTE Retrieving this result is very slow (takes over a minute). We will improve it, but currently you should not request this more often than about once in 15 minutes. If you request this resource too often, a HTTP 429 error is returned.


Example:

{

    "interval_start": "2012-03-13T21:00:00",

    "interval_end": "2012-03-14T10:00:00",

    "analysis_complete": true,

    "percent_analyzed": 100.0,

    "last_analysis_end_time": "2012-03-14T09:59:52",

    "percent_signal_covarage": 100.0,

    "respiration": [

        [

            8271.24, // Timestamp, seconds since interval_start

            "bcg",   // Channel (there may be several in some sensors)

            3.5,     // The length of the respiration cycle measured

                     // from minimum to minimum

            3.45,    // The length of the respiration cycle measured

                     // from maximum to maximum

            532.504712648 // The amplitude of the respiration cycle

        ],

        [

            8317.84,

            "bcg",

            3.25,

            3.05,

            544.509827026

        ],

        … // Rest of the respiration results

    ],

    "presence": [

        [

            0.0, // Timestamp, seconds since interval_start

            0    // 1 if person is present in bed, otherwise 0

        ],

        [

            8220.0,

            1

        ],

        [

            40512.0,

            0

        ],

        … // Rest of the presence data...

    ],

    // Instant heart rate, i.e. bpm computed from interval between two

    // single heart beats (not averaged)

    "ihr": [

        [

            8245.396667,  // Timestamp, seconds since interval_start

            71.1462450595 // Instant heart rate value

        ],

        [

            8246.24,

            75.9493670885

        ],

        … // Rest of the instant heart rate data

    ],

    // Actigram, zero-crossing mode

    // Basically, it means the times of movements above certain threshold

    "binary_actigram": [

            8220.0,  // Timestamp, seconds since interval_start

            8223.0,

        … // Rest of the binary actigram data

    ]

}

5.8 /api2/user/<username>/results?start=<time>&end=<time>

Get detailed vital sign analysis results from given time interval. This returns data in same format as the results resource described in chapter 5.6, but you can request data from arbitrary interval.

Get parameters

start=YYYY-MM-DDTHH:MM:SS

Start time of the interval, e.g. “2012-04-18T10:00:00”

end=YYYY-MM-DDTHH:MM:SS

End time of the interval

5.9 /api2/user/<username>/<year>/<month>/<day>/signal.bson

Get raw ballistocardiography signal (BCG) from one night.

The BCG signal is the raw movement signal measured by the sensor. It contains several channels. The channels may be different in different device models and versions. In current version, the signal contains the following channels:

This data is in BSON (binary json) format due to performance considerations. The following example shows the data structure as it is when loaded from BSON format.

NOTE Retrieving this result is very slow (takes over a minute). We will improve it, but currently you should not request this more often than about once in 15 minutes. Otherwise you will receive a HTTP 429 error.


Example:

{

    "interval_start": "2012-03-13T21:00:00",

    "interval_end": "2012-03-14T10:00:00",

   

    "channels" : {

        "lo_gain" : {

            "sample_rate" : 140,

            "data_type" : "int16",

            "sample_data" : "<data>"

        },

        "lo_gain2" : {

            "sample_rate" : 140,

            "data_type" : "int16",

            "sample_data" : "<data>"

        },

        …

    }

}

The channel data types specify how to interpret the binary sample_data field. For example, in Python you can extract the data using Numpy:

>>> import bson, numpy

>>> data = bson.loads(bson_data)

>>> channel_1 = numpy.fromstring(data["channels"]["lo_gain"]["sample_data"], numpy.int16)

>>> channel_1

array([0, 0, 0, 0, … ], dtype=int16)

5.10 Beddit Lab organization related resources

Beddit Lab is a service targeted for professional users of Beddit. Beddit Lab introduces the concept of organizations into the Beddit system.

Organizations can have members and clients. The organization members may create new clients, and organization members have access to clients sleep and other information.

The organizations and their members are managed using the Lab web application. It is found in http://app.beddit.com/lab.

5.10.1 /api2/organization/

List the organizations in which the currently authenticated user is a member.

Example response:

[

    {

        "website": "http://www.beddit.com/",

        "description": "Beddit demo organization",

        "id": 1,

        "url": "https://api.beddit.com/api2/organization/1"

        "name": "Beddit demo"

    },

    ...

    // Additional organizations which the user belongs to

]

5.10.2 /api2/organization/<organization_id>

Show the given organization’s information.

Example response:

{

    "website": "http://www.beddit.com/",

    "description": "Beddit demo organization",

    "id": 1,

    "url": "https://api.beddit.com/api2/organization/1"

    "name": "Beddit demo"

}

5.10.3 GET /api2/organization/<organization_id>/client

List the clients of the given organization

Example response:

[

    {

        "client_url": "https://api.beddit.com/api2/organization/1/client/4",

        "archived": false,

        "user_url": "https://api.beddit.com/api2/user/mikko",

        "clientship_started": "2012-05-14 11:12:56",

        "clientship_ended": null, // Date and time the clientship been ended

        "id": 4,

        "user_declined": false // Has the user cancelled the clientship?

    },

    …

    // List of other clients

]

5.10.4 POST  /api2/organization/<organization_id>/client

Create a new client for the organization

Parameter

Required

Description

username

Yes

Less than 30 characters, letters, numbers and @ _ - . allowed

first_name

Yes

Client’s first name

last_name

Yes

Client’s last name

email

Yes

Client’s email address

language

Yes

Language code. Options are:

"fi" for Finnish

"en" for English

"sv" for Swedish

"zh-cn" for Simplified Chinese

timezone

Yes

Timezone location name, e.g. “Europe/Helsinki”. A list of options can be found in http://twiki.org/cgi-bin/xtra/tzdatepick.html

5.10.5 GET /api2/organization/<organization_id>/client/<client_id>

Get one client’s information.

Example response:

{

    "client_url": "https://api.beddit.com/api2/organization/1/client/4",

    "archived": false,

    "user_url": "https://api.beddit.com/api2/user/mikko",

    "clientship_started": "2012-05-14 11:12:56",

    "clientship_ended": null,

    "id": 4,

    "user_declined": false

}

6. Streaming API

BETA We may still make changes to this. If you have questions or feedback, please drop us a line!

The streaming API can be used to follow measurements in real-time (within a few minutes). The API uses HTML5 Server sent events (see http://dev.w3.org/html5/eventsource/).

You should only keep a minimum number of connections open. To follow several users, list users in the url, and do not open separate connections for each user.

6.1 /api2/user/<username>[,<username2>,...]/stream

Follow updates from given username or list of usernames.

Optional GET parameters:

include=presence,ihr

Comma-separated list of result fields for which to receive messages

exclude=noise,luminosity,temperature

List of result fields to exclude

Only one of include and exclude parameters may be present. By default, all fields are included.

Events

Currently, the API sends events named results. The data payload is in JSON format. It contains fields which are same as in the results resource, and they are not repeated in this example. The timestamps in the results are seconds from the interval_start. Only fields which contain new results are present in the message.

Note that the ihr and respiration fields contain the individual heart beats and respiration cycles. If you intend to e.g. measure heart rate, you should probably apply some averaging to the data.

Example message data:

{

    "username" : "myuser", // The followed user to which this is related

    "interval_start" : "2012-03-13T21:00:00",

    "interval_end" : "2012-03-13T21:00:30",

    "respiration" : [ … ], // List of respiration results

    "presence" : [ … ], // 0: Not in bed, 1: In bed, 2: Unknown (no signal)

    "ihr" : [ … ],

    "binary_actigram" : [ … ],

    "noise" : [ … ],

    "luminosity" : [ … ],

    "temperature" : [ … ]

}

Example of processing the messages in Javascript:

        

if (!!window.EventSource) {

    var source = new EventSource("/api2/user/<user>,<user2>/stream");

    source.addEventListener("results", function(event) {

        var data = JSON.parse(event.data);

        if ("ihr" in data) {

            // Process heart rate results

        }

        … // Process other results, if present

    }, false);

                

    source.addEventListener('open', function(e) {

        console.log("Connection opened");

    }, false);

    source.addEventListener('error', function(e) {

        if (e.readyState == EventSource.CLOSED) {

            console.log("Connection closed");

        }

    }, false);

                

} else {

    console.log("Event source is not supported by your browser");

}

Of course, you can process the same stream easily in any server or desktop application. Please see the W3 documentation for details about the data format.

7. Error responses

Generally, the API returns HTTP 200 response when everything went fine, and otherwise an appropriate HTTP error code.

Note that the error response is always returned in JSON format, even for the signal resource, which normally returns a BSON response.

7.1 HTTP error codes

Error code

Description

404 NOT FOUND

The resource was not found

400 BAD REQUEST

There was something wrong with your request parameters

403 FORBIDDEN

You do not have access rights for this resource

429 TOO MANY REQUESTS

Your access is being throttled, because you have tried to access a resource too often. Please see documentation for each resource for information about reasonable usage limits.

500 SERVER ERROR

The server encountered an internal error

7.2 Error JSON responses

We are working to add sensible JSON content also to all error responses (more detailed error code, and human readable error message).

Example error response:

{

    “error” : “not_found”,

    “error_message” : “The requested user was not found”

}

If you get an error response in JSON format (mimetype text/json), it will always contain the keys error and error_message.

Error

Description

not_found

The requested resource was not found

permission_denied

You don’t have permission to access it

no_data

There was no data for given time

no_device

The user does not have device set up

invalid_parameters

There was something wrong with your request parameters

unauthorized

You did not provided needed authorization information with the request. You need to provide a valid access_token.

8. Tips

curl is a great command-line program for testing out the API calls.