_    _                    _    _
 | |  | |                  | |  (_)
 | |__| | _____  _____  ___| | ___ _ __
 |  __  |/ _ \ \/ / _ \/ __| |/ / | '_ \
 | |  | |  __/>  < (_) \__ \   <| | | | |
 |_|  |_|\___/_/\_\___/|___/_|\_\_|_| |_|

This column will contain helpful example queries and responses, along with additional information to help you understand how the REST API works.

This documentation pertains to API version 3.3.x

This is the Hexoskin REST API reference Wiki.

The Hexoskin REST API allows you to interact and manipulate your Hexoskin data through HTTP requests. This includes accessing biometrics and user information, but also annotating data, viewing advanced reports, fetching metrics, and more.

Click here to access data resources doc directly.

Before getting started

Other ways to access your Hexoskin data

If you ended up here, you are probably interested in doing a bit more with your Hexoskin biometrics. However, if you just want to download your data, there might be an easier way than using the REST API. You can download your Heart Rate, Breathing Rate, Minute ventilation, Activity and cadence in CSV format, and the rest of the data in binary form directly from the dashboard. We provide scripts for Python and Matlab/Octave to help you convert them to .csv files, if you need. Have a look at this page and see if it’s sufficient for your needs.

Additionally, there is a Python client available, accessible on Bitbucket. If you have implemented the API in another language and want to share it, be sure to write us an e-mail at and we’ll put it up along with the Python client.

Getting an API access

To use this REST API, you’ll need an API key or an OAuth access. The API supports both OAuth1 and Oauth2. If you don’t have an access already, email us at with your project name and a quick description of what you want to do, and we’ll happily create you one. Make sure to create an account on our servers first - our access keys needs to be associated with an user.

So… What’s a REST API?

If you’re new to using APIs, you’re at the right place. You’ll need to understand the concept of REST API before you can do anything. Reading this will help, but you will probably have a little homework to do if you’re starting from scratch. If you already know what we are talking about, great! Jump ahead to the Hexoskin Getting Started section to get going.

For those still here, REST stands for REpresentational State Transfer and describes a way to make data accessible, generally via the Internet. A website like is something you’re most likely already comfortable with. It’s a page that contains some information. To go to the developer section of the website, you can obviously click on a few button, but you can also add /pages/developers to the previous URL, and you’ll end up in the developer section. You just went from the general website to the developer-oriented page. A REST API works in a very similar fashion. The entry point of the REST API is, and appending information at the end will bring you further down. For example, asking for will return you your own account’s information. The information is returned as a JSON object, a standard format for such kind of information.

Something quite neat about REST APIs is that you can add arguments that will modify what the REST API returns to you. For example, take The response you receive will contain all training routines available to perform. But what if you want to look at the training routines that you have used? Well, looking at the trainingroutine documentation, you see that there is a filter just for that. You can then query, and voilà, you have used a filter to modify what the REST API returns to you.

One final thing to mention : While your web browser will allow you to fetch information from regular websites, our REST API requires additional information that the browser doesn’t provide. To interact with the REST API, you need to be using some programming language that allows you to specify some headers to the HTTP request you are making. That will allow you to GET, POST information, DELETE and PATCH some resources that you want modified.

Getting started

Overview and Technology

The API is built using Django and Tastypie. As such, the methods of querying the API follow the implementation patterns of Tastypie.

We have attempted to conform to RESTful practices as much as is practical. There are a few instances where a judicious departure has been indulged but overall you can assume things will work RESTfully.

API keys and OAuth requests

To perform (almost) any request, you need to authenticate either via API keys, basic auth or Oauth2. The API keys/Oauth2 tokens have their endpoint, located here so you can view the keys associated with your account. When starting to perform requests, make sure your key’s status is either ‘oauth2’, ‘oauth1’ or ‘apikey’, depending on which one you want to use.

API Key identification

An example POST request with an API key would look something like this :

User-Agent: HTTPTool/1.0
Content-Type: application/json
Authorization: Basic ZmVtb2FjY291bnRaZGVtby5jb256ZGVtb3Bhc3N3c3Jp
X-HEXOAPIKEY: 3X4mP1ePu6licK3y
X-HEXOAPISIGNATURE: 3x4mPl3ShA15igN4tUr33x4mPl3ShA15igN4tUr3

When performing a request, it has to be signed with your private API key, the timestamp, and the URL. Your API key has a public and a private portion. Never send the private key, only use it to sign the request. Send the public key. When looking at your key via the endpoint, your public key is the ‘client_id’ and your private key is the ‘secret’.

To use the keys, you add three headers to each request:

Note : X-HEXOTIMESTAMP has to be a standard timestamp, it must be not be multiplied by 256 like the timestamp mentioned bellow

The signature is a SHA1 hash of the the private key, timestamp, and the URL (the entire URL, including the GET arguments). The order, of course, is very important. To help you remember, it’s alphabetic: Key, Timestamp, Url.

For example, if your private key is 3x4mPl3pR1v4tEK3y3x4mPl3pR1v4tEK3y, the timestamp is 1400000000 and the URL you want to query is, the pre-hash signature would be 3x4mPl3pR1v4tEK3y3x4mPl3pR1v4tEK3y1400000000, and the resulting hash would be 88c7a8e7b35f145ddac98f861476d89dc6604fb3.

OAuth General considerations

After getting your OAuth client keys, make sure to set the redirect url. To do that, you can send a PATCH on your client (located at[client id]/) on the “redirect_uris” field. The body of the request should look something like {"redirect_uris": ["",""]}

During the OAuth token authorization process, only URLs already registered in the server will be accepted.

You can always view your list of tokens by looking at

OAuth2 Authentication

OAuth 2 is the most streamlined version of both OAuth processes. you can find more details here: The URLs used during the process are:

After receiving your authenticated token, you can query allowed resources by adding the “Authorization: Bearer [token]” header to your request.

API versions

A very important factor when developing is making sure you are querying the correct API version. The API has a default “current” version running which is the most up-to-date available. If you start developing, you might want to think about specifying an API version in your HTTP header. Failure to do so might break your code, if a resource you are using changes between two API versions.

To specify the API version, specify X-HexoAPIVersion: X.X.X, where X.X.X is the version you want to use.


Timestamps are represented a little differently than is usual. Instead of representing the number of seconds since Jan 1, 1970 UTC (UNIX timestamps), they represent the number of 256ths of a second since Jan 1, 1970 12:00:00pm UTC. In other words, they are a regular epoch timestamp multiplied by 256. All timestamps in the system are like this unless explicity noted. This modification allows the ECG’s timestamps to be stored as integers, since it has the highest sampling rate, at 256Hz.

Note: The HexoTimestamp is only for the request parameters, it is not used for the `X-HEXOTIMESTAMP` authentication header

Making Requests

All requests are conducted over SSL. Any non-SSL requests received are forwarded to HTTPS.

Currently, only JSON is supported for non-data resources. For data resources, JSON, CSV and octet-stream are supported, though JSON and CSV have limitations (see data). Set your headers accordingly.

On the whole, interactions with the API behave as described in Tastypie’s documentation. A couple of notable restrictions are:

DELETE and PUT requests to list views are always denied. PUT to a detail view of a non-existant instance will not attempt to create the instance, it will result in a 404. POST requests to detail views are always denied.

Retrieving Resources

List views

A typical list view, for example taken from looks like:

{ "meta": { "limit": 20, "next": "/api/datatype/?limit=20&offset=20", "offset": 0, "previous": null, "total_count": 95 }, "objects": [ { "dataid": 208, "hexo_freq": null, "info": "Recorder start annotation.", "name": "RECSTR_ANNOT_CHAR", "resource_uri": "/api/datatype/208/" }, { "dataid": 16, "hexo_freq": 1, "info": "1 to 3 leads ECG channel(s).", "name": "ECG_CHANNEL_CHAR", "resource_uri": "/api/datatype/16/" }, { "dataid":"..." } ] }

To get a list of resources, you make a GET request to the resource’s endpoint. For instance, to retrieve datatypes you would access the following resource:

Resources are represented as URIs. URIs generally conform to the following model:

/api/[resource name]/

For example, all the datatypes are found by issuing a GET request to:

/api/[resource name]/[ID]/

This is a “list view” because it will return a list of all the instances of that resource that the current user is allowed to see.

Note that the resource name is singular and there is a trailing slash. Also note that by default, a list’s limit of returned objects is 20. To change that, you have to specify the ?limit= argument in your GET query. The response will never return more than 1000 objects, except for data resources, where that limit is 65535.

Requests to lists return an object containing two members; meta contains information about the results and objects contains the actual results. A sample result from /api/datatype/?offset=20 is shown on the right panel.

As you can see, the meta object tells us how to page through the data. You can roll your own paging routines of course, but you may also use the next and previous attributes of the meta object. The limit and offset variables are passed in the GET to determine which page to retrieve.

Filtering and Ordering

An example query containing a filter:,HXSKIN1200002049

{ "meta": { "limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 13 }, "objects": [ { "data": "TfzfJ1QAAABIWERFVi1BVVRPTXwAAAAAhQoAAEZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGAQAFAA==", "data_status": {}, "dev_id": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "device": "/api/device/HXSKIN1200002115/", "end": 361451358544, "firmware_rev": "1.0.5", "id": 43419, "n_uploaded_timelines": 0, "npages": 71710, "resource_uri": "/api/record/43419/", "soft_protocole": 0, "soft_uid": "HXDEV-AUTO", "start": 361446243405, "start_date": "2014-09-28T10:16:28+00:00", "status": "complete", "user": { "email": "", "first_name": "Athlete", "id": 1511, "last_name": "Hexoskin", "profile": "/api/profile/1460/", "resource_uri": "/api/user/1511/", "username": "" } }, { "data":"..." } ] }

Variables for filtering and ordering the results are also passed through the GET arguments. You can filter on any combination of fields and filter types in the Filtering Options of a resource. Refer to the ‘Filtering Options’ section of endpoint’s documentation to determine what these are for that resource. For example, the record resource supports the following filtering options:

You use a filter type by passing a GET argument of [column]__[filtertype]=[value]. So to view a list of records that contains only records that started on or after a start timestamp of 347631277170, you would append start__gte=347631277170 to the URL like this:

If no filtertype is specified, exact is assumed. so user__exact=/api/user/99/ is the same as user=/api/user/99/. For simplicity, user=9 will also work.

Ordering works in a similar fashion. Columns which support ordering are listed in each endpoints' documentation under ‘Sorting Options’. You may pass order_by= followed by a comma-separated list of columns. The sort order is ascending by default, to make the sort order descending prepend the column name with a -. So to add a descending order to our record query, you would make the following request:

Detail views

A typical detail view, this one taken from, looks like :

{ "dataid": 208, "freq": null, "info": "Recorder start annotation.", "name": "RECSTR_ANNOT_CHAR", "resource_uri": "/api/datatype/208/" }

You may query a specific instance of a resource by accessing its URI. You are strongly encouraged to use the resource_uri attribute that is provided with each resource, however if you prefer to create them, they generally follow the pattern of the list URI with the ID appended:

/api/[resource name]/[ID]/

So to access the Recorder start annotation datatype directly, you would make a GET request to:

Note that the detail view does not contain a meta and object attribute, the resource instance is returned directly.

Create, Update and Delete

For example, a POST on annotation with the following content:
{‘datatype’: ‘4096’, ‘start’: 123456, ‘user’: 835, ‘annotation’: ‘Hey guys!’}
will return the following content:

{ "annotation": "Hey guys!", "datatype": "/api/datatype/4096/", "id": 61353, "last_update": 362161472635, "record": null, "resource_uri": "/api/annotation/61353/", "start": 123456, "start_date": "1970-01-01T00:08:02+00:00", "user": "/api/user/835/" }

Creating an instance of a resource is achieved by issuing a POST or a PATCH request to the list view of the desired resource. If the instance is created is successfully, you will receive a 201 with the location of the new resource in the Location header. For many resources, the instance will be in the body but sometimes, primarily in cases where there is a lot of data involved, the instance representation is omitted.

Not all resources support PATCH requests and some don’t support creation at all! Please refer to the documentation for each resource to see what methods are supported and which fields must be supplied.

To update an instance, you may send a PUT or a PATCH to the URI of the resource instance you wish to update. As with creation, support for different methods vary between resources, be sure to check the documentation.

If you use the PATCH method, it is not necessary to supply the entire object, you may supply only the fields you wish to change. If you use the PUT method you must provide a complete object to replace the existing one.

Deleting, as one would expect, is done by sending a DELETE request to the resource instance’s URI.

Cached Content

The API caches results to improve performance. If your are receiving a cached response, the X-HexoCache header will be present in the response and will contain a timestamp (normal timestamp, not a HexoTimestamp) of the time it was cached.

Error Codes

400 Bad Request

There is a problem with the data or the format of the data supplied.

401 Unauthorized

Your authentication failed.

403 Forbidden

Your user is not allowed to do what your are trying to do.

404 Not Found

The resource does not exist or you are not allowed to see the resource instance requested.

405 Method Not Allowed

You have attempted to use a method which is not allowed on the given resource.

500 Server Error

The API has encountered an error.

Operations Examples

This section contains example operations, displaying some functionalities of the REST API. However, before jumping in, there will be a quick overview of the Hexoskin ecosystem (some resources and their interactions). Read away if this is interesting to you, or jump straight to the examples.

Hexoskin ecosystem overview

At this point, you might have some data collected or are looking at the demo account, and are wondering: What are the different building blocks of this API and how do they interact together? Is there anything important that I should know before getting into this? Before getting in the detailed filters and query descriptions, this section will give you a quick overview of the Hexoskin ecosystem.

For starters, to find all hexoskin-collected data you have to specify a timestamp range and a user. When a user connects his hexoskin to the shirt, a Record is created. A Record consists, among others, of a user, and a start and end timestamp. Because of that, when asking for data, you can either query directly by timestamp, or instead ask for a record’s data directly. Since records are always created over Hexoskin-collected data, you should never find any data outside of a record. Since it comes from the mobile phone directly, all GPS data is instead aggregated in the Ranges. Speaking of which, Ranges, often referred to as activities, are a way for you to annotate what you were doing at a given time. Ranges have, among other attributes, a name, a start and end time, and an user. When using the mobile application, setting the activity will start the GPS data collection if applicable, and that data will be available for that Range.

All Hexoskin-collected data is separated in datatypes. Each datatype has it’s own ID, and when accessing data, you pass a list of datatype IDs in the request.

Some Ranges will trigger additional processing, making more data available to you. Depending on the activitytype of the trainingroutine of the range applied, HRV, sleep positions, and more become available. Refer to the activitytype documentation to see what makes which data available. The relationship between ranges, trainingroutines and activitytypes is very simple : An activitytype is a broad category that regroups multiple trainingroutine together and that tells us if some special processing must be done. For example, Resting is an example of activitytype and tells us to process HRV. trainingroutine are just a specific type of activity. The trainingroutine indicates if the GPS should be started when using the application via the ‘geo’ field in metadata, but otherwise, it’s just a slightly more specific categorization of the range. ranges are the instance of a trainingroutine. When performing an activity and annotating it on the phone, a range is created, allowing the user to easily find back “that time” he did “that thing”.

In the API, there is a coach-athlete and friend relationship. They differ by the kind of permissions they provide to the affected users. As someone’s friend or as his coach, his data will appear in the responses, unless you filter them out. Athletes do not see the coach’s data.

Getting user profiles

{ "meta": { "limit": 1, "next": null, "offset": 0, "previous": null, "total_count": 1 }, "objects": [ { "email": "", "first_name": "Athlete", "id": 1511, "is_staff": false, "last_name": "Hexoskin", "profile": { "date_of_birth": "1980-01-01", "fitness": { "fitness_percentile": 50, "height": 1.82, "hr_max": 183, "hr_recov": 0, "hr_rest": 73, "vo2_max": 42, "weight": 78 }, "gender": "M", "height": 1.82, "id": 1460, "preferences": null, "resource_uri": "/api/profile/1460/", "unit_system": "metric", "weight": 78 }, "resource_uri": "/api/user/1511/", "username": "" } ] }

There are two ways of accessing user information. Using

will always return you only the authenticated user’s data. However, if you have friends or athletes under your account, you can see their account information with

The list you receive contains summaries of all users you can see’s informations. This includes the authenticated account, and any friend or athlete that user has. In this summary view, the profile is returned as an URI. To access a specific user’s profile, either ask for[ID]

or get the detail view of the user’s data with[userID]

Be sure to not mix up the user’s ID with his profile’s ID, as they will most likely differ.

Getting biometric data - JSON,33&record=37700

[ { "data": { "19": [ [ 359840227126, 70 ], [ 359840227382, 71 ], ["..."] ], "33": [ [ 359840227126, 12 ], [ 359840227382, 13 ], ["..."] ] }, "user": "/api/user/1511/" } ]

Because Hexoskin records lots of data, all hexoskin-recorded data is neatly organized in separate datatypes that you can query individually. You can view a list of all existing datatypes by using :

Because it is returning a list view, the previous call returns a maximum of 20 objects. If you want to see a different subset, check out List views for more information.

When you know which datatypes you need, you need to decide for which time frame you want them. To do so, you can pass a range or record. To get a list of records, for example, you can call :

Now that you know what data you want, and for which record, you can query as follow, using the IDs of the resources you want :,33&record=37700

The previous query will return the datatype IDs 19 and 33 (heart rate and breathing rate) for record 37700.

Note that when asking for JSON, all data is limited to return a maximum of 65535 points. If the time range you are asking for would contain more points (such as 257 seconds or more of 256Hz EKG, for example), the data returned is subsampled appropriately to return the max number of data points. If you don’t want to have to parse through data or want to receive everything not subsampled, use the Binary format (described next) instead.

Getting biometric data - Binary

The following Python script converts your binary files data and prints it.

# Decode WAV file
import struct
data = struct.Struct("h")  #Binary format : short
with file('record_37700/ECG_I.wav', 'r') as f:  # Skip WAV headers
    bytes =
    while bytes:
        print data.unpack(bytes)
        bytes =

Output for synchronous data:

#Decode asynchronous file (.hxd)
import struct
data = struct.Struct("Qq") # Binary format : Unsigned long long, long long
with file('record_37700/RR_interval.hxd', 'r') as f:
    bytes =
    while bytes:
        print data.unpack(bytes)
        bytes =

Output for asynchronous data:
    (85, 256)
    (154, 69)
    (234, 80)

If you are interested in the full, unsubsampled raw data, you might want to consider getting it using the Accept: application/octet-stream header. This will return your data in compressed zip binary format. So for example, you wanted to download the raw ECG and RR interval for a given record, you would first call,18&record=37700

with the header Accept : application/octet-stream, which will write the output to a Zip file.

The previous call sets the Accept header to application/octet-stream to download the data in the binary format, then outputs the data to the record_37700 zip file. Datatype 4113 stands for ECG, and 18 for RR interval.

The next step is to unzip the compressed file. You can call


which will create the record_37700 directory, containing ECG_I.wav and RR_interval.hxd, our binary files.

In this case, the ECG is synchronous, while the RR interval data is asynchronous.You can use the example on the right to guide you and find the equivalent to decode both files in your favorite programming language.

As mentionned in the data resource documentation:

“Syncronous data is returned as a RIFF/WAV file and asynchronous data is returned as a series of timestamp/value pairs encoded as long longs (8 bytes).” This means that synchronous data does not contain the timestamps. You can easily know when a sample has been acquired though, because you can access the record start and know the sampling rate. For the asynchronous data, the first column represents the offset from the record’s start, in HexoTimestamp.

Getting GPS data

{ "meta": { "limit": 20, "next": "/api/track/?limit=20&offset=20", "offset": 0, "previous": null, "total_count": 10 }, "objects": [ { "area": null, "distance": 656.763124754487, "id": 80, "name": "", "range": "/api/range/58979/", "resource_uri": "/api/track/80/", "source": "", "user": "/api/user/805/" }, { "area":"..." } ] }

{ "meta": { "limit": 20, "next": "/api/trackpoint/?track=80&limit=20&offset=20", "offset": 0, "previous": null, "total_count": 53 }, "objects": [ { "altitude": 42, "course": null, "horizontal_accuracy": 3.90000009536743, "id": 27720, "position": [ -73.6045937, 45.5308797 ], "resource_uri": "/api/trackpoint/27720/", "speed": 0, "time": "2014-08-29T09:25:15", "track": "/api/track/80/", "vertical_accuracy": null }, { "altitude": "..." } ] }

GPS data, collected by the mobile phone, is stored in the trackpoint endpoint. Whenever a range acquires GPS data, it creates a track object. You can list all available tracks using

Tracks contain a reference to the range that is associated with it. Once you know which range, and thus which track you want, just query

The trackpoint resource contains all GPS points related to the given track.

Additionnally, GPS data can be accessed via timestamps or time filters. The following two queries yields the same results :,366453822976 and,2015-05-12T19:50:46

Getting Metrics,44&record=37700

{ { "metrics": [ { "name": "activity_avg", "outputtype": "value", "resource_uri": "/api/metric/1/", "title": "Act Avg", "unit": { "id": 450, "info": "", "resource_uri": "/api/unit/450/", "si_long": "g,acceleration", "si_short": "g" }, "value": 0.158528803165781, "zone": 2, "zones": [ 0, 0.1, 0.2, 0.3, 0.4, 0.5 ] }, { "name": "heartrate_avg", "outputtype": "value", "resource_uri": "/api/metric/44/", "title": "HR Avg", "unit": { "id": 700, "info": "", "resource_uri": "/api/unit/700/", "si_long": "beats per minute", "si_short": "bpm" }, "value": 103.285529715762, "zone": 6, "zones": [ 65, 67, 70, 72, 74, 88 ] } ], "timeranges": [ { "end": 359840821814, "start": 359840226870, "user": "/api/user/1511/" } ] }

Along with the actual data from the hexoskin, metrics are also available. Metrics are a way to summarize data in a single values or histograms. A few example of metrics are heart rate average, max activity, minimum breathing rate and so on. A few noteworthy metrics are :

You access the full list of metrics using a similar pattern than for datatypes :

When you have your own list of favorite metrics, you can query the following (replacing “1,44” by your very own list),44&record=37700

and the metric data will be appended to the record’s information.

Analyzing HRV

{ "metrics": [ { "name": "HRVLFnorm_avg", "outputtype": "value", "resource_uri": "/api/metric/173/", "title": "HRVLFnorm avg", "unit": { "id": 3, "info": "", "resource_uri": "/api/unit/3/", "si_long": "percent", "si_short": "%" }, "value": 69.8, "zone": 2, "zones": [ 50, 60, 70, 80, 90, 100 ] } ], "timeranges": [ { "end": 361674727680, "start": 361674650880, "user": "/api/user/36/" } ] }

First off, you have to know HRV is only computed for select ranges, in select conditions. This is because HRV is a very picky measure, requiring very high quality data, and a large RR intervals sample. As such, a range will have HRV metrics available only if :

Once a range meets those criterions, the HRV will be calculated on the server and be available to access. Using the Getting metrics method above, try accessing metric id 50, which is the HRV average. A returned value of -1 means that the HRV has not been calculated correctly.

In addition to metric ID 173, there are a few channels that are related to the HRV that can be accessed. They are described in the HRV section.


TCX and FIT exchange formats

An important aspect of any fitness platform is interoperability. As such, the API supports TCX and FIT format import and export. Both Range and Training Routine export/import are supported.


When querying a Range or a Record via /api/record/[id]/ or /api/range/[id]/ on the API, you can specify the following headers. Instead of returning a JSON response, the server will return either a TCX or FIT file that contains your data. It is also possible to query /api/trainingroutine/[id]/ to get a TCX or FIT representation of a given training routine.

You can refer to these format’s standards for more details regarding the format. Note that for TCX format, the output will contain data for every second (heart rate, breating rate, tidal volume, minute ventilation and energy in Watts), and GPS points only where available. For FIT files, there will only be data at moments where GPS position has been reported, leading to a much smaller file size.


In addition to being able to export the TCX/FIT files, the API supports import of those formats. Using the following headers :

you can post your activity or training routine to You can directly send the content in the raw body of the POST request, or send it as a binary. The response will contain a resource_uri field that you can then query to follow the uploading progress of you file. This will be located in something like[upload id]/

When importing a Range this way, the system will always create a range. If the file contains biometric data (Heart rate, breathing rate, etc…), a record will also be created and will be in the response. Laps will be created as ranges too, but their rank will be 1 (the top-level range’s rank is always 0).

Data Export formats

When querying the /api/data/ endpoint, the default response format will be JSON. However, you can specify the following headers in your query to receive the data in the specified formats:


The full, latest list of available (auto-generated) resources is located at In case anything seems off in the documentation below, refer to that page.

The full list of available datatypes is available through /api/datatype/?limit=0

Biometric Resources

[ { "data": { "4113": [ [ 361446243405, 1715 ], [ 361446243484, 1423 ], [ ... ] ] }, "user": "/api/user/1511/" } ]

This section describes the various biometric resources. All datatypes are available either through the URLs described in each respective section, or alternatively through the /api/data/ endpoint described just below. Using the ?datatype__in= filter will allow you to request more than one datatype easily.

The following sections will link to the most up-to-date documentation for each resource. The broad category for each resource will briefly describe the relationship between the various resources under it.



The data endpoint is the easiest way to access biometric data, as it allows you to make a single query to fetch multiple different datatypes, provided you know the datatype’s IDs. An example query using data would be:,33,34&record=37700

which would return datatypes 19, 33 and 34.

You can check out the data export format section for additionnal export formats beyond JSON.



The datatype resource allows you to view a list of available datatypes.

The most common datatypes IDs are as follows:

1Hz Data:

Raw data:


ECG is the key for all resources here. From the ECG, we detect the QRS complex (the peak that represents a heartbeat). The time interval between these QRS complexes is available through the RR interval resource. The RR interval is used to compute the Heart rate.

The Heart rate status shows various flags related to signal quality to help you detect if the data is reliable or not.

ECG Raw Data,

[ { "data": { "4113": [ [ 361446243405, 1715 ], [ 361446243484, 1423 ], [ ... ] ] }, "user": "/api/user/1511/" } ]


Heart rate


Heart Rate Status



[ { "data": { "1000": [ [ 359840227126, 32 ], [ 359840227382, 32 ], [ 359840227638, 40 ], [ 359840227894, 32 ] ] } } ]

In that example, the 32 value translates to : 0010 0000, which means only the 6th flag is up. The RR interval is unreliable at that point.

Next, a value of 40 is given. The bit representation is 0010 1000. That means the RR interval is unreliable and that the signal is saturating.

Later on (not shown in this excerpt of the data), the value falls to 0, which means that the data is in top condition and ready for interpretation.

Heart rate status is a bit of a special channel : it contains information on the perceived quality of the data. The value is returned as an Integer, but the bits is what needs to be interpreted, as each bit represents a potential flag, explained below. The Hexoskin uses those flags to know if the QRS detected are reliable or if they should be ignored. As such, there might be discrepancies between detected QRSes and the returned heart rate if some of the flags below have been set.

If you need, an example of how to interpret the data is given in the right-panel example.

Below are examples of what the ECG looks like when each kind of flags are up:


Disconnections looks like the following. Note the scale, the variations are extremely small.


Manageable 50-60Hz component looks like the following. Our QRS-detections algorithms can filter out this component and the QRS should be detected correctly.

However, in the following case, the 50-60Hz component is too important, even heavy filtering can not get rid of the noise.


Spontaneous saturation looks like the following. It can happen if one or more of the shirt’s electrodes stop making contact with the skin for a few moments. The next QRS might be missed, but the QRS detection algorithm should recover quickly.

In the following case however, the saturation is too important for the algorithm to detect anything reliably.


Movement artifacts looks like the following. Red X'es represents QRS detections - As you see sometimes this kind of noise can be interpreted as a QRS, although it will not always be the case, depending on the spectral components of the noise. QRSes detected while the movement artifact flag is up should be interpreted with caution.


Finally, our algorithm expect a certain regularity of the QRS intervals. If a detected QRS would result in a suspicious RR interval, the unreliable RR flag is set. Sometimes, these can be due to some artifact like in the previous figure, but it can be caused by actual suspicious RR intervals, as in the sample shown below.



RR interval


From the raw respiration sensor measurements, we automatically detect Expirations and Inspirations. The tidal volume is derived from the difference between the inspiration and expiration values. The average Tidal volume, multiplied by the breathing rate, results in the Minute Ventilation.


[ { "data": { "37": [ [ 359840228406, 571.04 ], [ 359840228662, 571.04 ], [ ... ] ] }, "user": "/api/user/1511/" } ]

Respiration Raw Data


Breathing rate






Minute ventilation


Tidal volume


Breathing Rate Status


To compute the Activity, we filter out the low-frequency gravity component of the raw accelerometer data, then average the modulus of the three axis.

Using the raw measurements, we detect Steps automatically. The average time between steps yields the Cadence.

Finally, Sleep Positions are calculated during sleep.

Raw Accelerometer data








Device position


Sleep Position

[ { "data": { "270": [ [ 362306334580, 1 ], [ 362306335092, 5 ], [ ... ] ] }, "user": "/api/user/XXXXX/" } ]


Sleep Phases



Although HRV is calculated by ECG and might be categorized under heart-rate related, it deserves its own section. Note that HRV-related metrics are only calculated for ranges of the correct activity type (12 for sleep or 106 for Rest test).









NN Interval


NN Over RR






GPS Data Resources

GPS data is acquired and available when a Range requires geolocation.


{ "meta": { "limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1 }, "objects": [ { "area": null, "distance": 13.9953509448312, "id": 1, "name": "", "range": "/api/range/48328/", "resource_uri": "/api/track/1/", "source": "", "user": "/api/user/805/" } ] }

The track object is the container for the list of GPS points that were acquired during the range execution. Because GPS is only ON when executing certain training routine, make sure that the routine you want to collect the data from has the “geo” parameter set to true.


Track Point

{ "meta": { "distance": { "/api/track/1/": 13.9953509448312 }, "limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 2, "total_tracks": 1 }, "objects": [ { "altitude": 38, "course": null, "horizontal_accuracy": 4, "id": 2, "position": [ -73.598363, 45.5299156 ], "resource_uri": "/api/trackpoint/2/", "speed": 5.9548716545105, "time": "2014-08-14T05:25:17", "track": "/api/track/1/", "vertical_accuracy": null } ] }

Trackpoints are the actual GPS location points measured by the phone during the range or record.


Structural Data Resources

{ "activityattributes": [ { "attrtype": "user", "id": 1, "name": "distance", "resource_uri": "/api/activityattribute/1/", "unit": { "id": 103, "info": "", "resource_uri": "/api/unit/103/", "si_long": "kilometer", "si_short": "km" }, "user": null, "value": null }, { "attrtype": "user", "id": 2, "name": "fatigue", "resource_uri": "/api/activityattribute/2/", "unit": { "id": 2, "info": "Qualitative scale, select between 1 and 10", "resource_uri": "/api/unit/2/", "si_long": "", "si_short": "" }, "user": null, "value": null }, { "attrtype": "user", "id": 3, "name": "energy", "resource_uri": "/api/activityattribute/3/", "unit": { "id": 400, "info": "", "resource_uri": "/api/unit/400/", "si_long": "joule", "si_short": "J" }, "user": null, "value": null } ], "created": "2014-09-08T17:42:42+00:00", "duration": "0:00:06", "end": 361010731008, "id": 61495, "last_modified": "2014-09-08T17:42:48+00:00", "metrics": [ { "id": 44, "name": "heartrate_avg", "resource_uri": "/api/metric/44/", "title": "HR Avg", "unit": { "id": 700, "resource_uri": "/api/unit/700/", "si_long": "beats per minute", "si_short": "bpm" }, "value": 69.3333333333333, "zones": [ 0, 114, 133, 152, 171, 250 ] }, { "id": 139, "name": "energyecg_vo2_kcal", "resource_uri": "/api/metric/139/", "title": "energyecg vo2 kcal", "unit": { "id": 551, "resource_uri": "/api/unit/551/", "si_long": "Calorie", "si_short": "Cal" }, "value": 0.022502796271686363, "zones": [] } ], "name": "bike", "note": "", "parent": null, "ranges": [], "rank": 0, "resource_uri": "/api/range/61495/", "start": 361010729472, "start_date": "2014-09-08T17:42:42+00:00", "status": "complete", "trainingroutine": "/api/trainingroutine/1/", "user": "/api/user/36/" }

{ "data": "Nh4myFMAAABIWERFVi1BVVRPNp4AAAAAJAAAAEZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGAQAFAA==", "data_status": {}, "dev_id": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "device": "/api/device/HXSKIN1200002070/", "end": 359840821814, "firmware_rev": "1.0.5", "id": 37700, "last_modified": "2014-07-17T20:16:50+00:00", "n_uploaded_timelines": 0, "npages": 8276, "resource_uri": "/api/record/37700/", "soft_protocole": 0, "soft_uid": "HXDEV-AUTO", "start": 359840226870, "start_date": "2014-07-17T19:38:06+00:00", "status": "complete", "user": { "email": "", "first_name": "Athlete", "id": 1511, "last_name": "Hexoskin", "profile": "/api/profile/1460/", "resource_uri": "/api/user/1511/", "username": "" } }

As mentionned in the Import/Export section, Ranges and Records can be download as more than just JSON. Refer to that section for more details.


Ranges are used to instantiate training routines. They label a time period with a name and a training routine. Since training routines have an Activity Type, these activity types are indirectly related to ranges. Some training routines requires GPS. If GPS data is collected, it will be found within the range. Ranges automatically contain activity attributes and metrics as prescribed by the activitytype of the training routine to which the range relates.

In the example on the right, the activity attributes have not been set, thus their value of null. On the other hand, metrics are populated automatically.



If an Hexoskin device has an user assigned, it starts a recording automatically when connected to a garment. The record represents the time period containing Hexoskin-related data.


Additional Info Resources



Activity Type

The activitytype attribute applies to a trainingroutine. It is an aggregator to group similar trainingroutines together. The activitytype dictates if any additionnal processing is applicable to the routine, such as :

The activitytype also controls which metrics are returned when querying a range. These metrics are always returned by default, and adding &include_metrics=... will append other metrics to that list. The table below summarizes which activitytype returns which metrics.

For example, if a range has trainingroutine 6 (jog), it means it belongs to activitytype 10 (Running). As such, when requesting that jogging range, metrics 44, 71 and 139 will be appended automatically in the response.


Activity Attribute

Activity attributes are additionnal data for ranges that needs to be manually entered. The activity attribute object is just the template, the actual instance is the Activity Attribute Value. As the name suggests, they are activitytype-related (meaning all ranges of the same activity type have the same activity attributes).


Activity Attribute Value








The list of metrics and their description can be found here :



Training Routine

{ "activitytype": "/api/activitytype/101/", "application_metadata": null, "description": "The 1 mile Rockport Walk test has been designed to estimate VO2max using a sub-maximal field test. The goal is to walk 1 mile as fast as possible", "id": 1011, "last_used": null, "metadata": { "geo": true }, "name": "1 Mile Rockport Walk Test", "resource_uri": "/api/trainingroutine/1011/", "steps": [ { "activitytype": "/api/activitytype/10/", "custom_target_high": 0, "custom_target_low": 0, "description": "", "duration_type": "distance", "duration_value": 1609, "index": 0, "intensity": "active", "name": "run", "target_type": "open", "target_value": 0 } ], "user": null }

Training routines consists of a name and an activity type. They also determine whether or not the GPS should be enabled via the “geo” field, in metadata. The training routine is just the template and are instanciated as Ranges.




User Related Resources

In this section, User Resources are endpoints used to access some User-related information. Operations are endpoints that you can use to trigger server operations, such as a password reset for a user.

User resources





Bundle Permission






Bundle Permission Request


These operations are not actual resources, in the sense that they trigger a process on the server, but you should not expect a response from them.

Change Email



Create User


Create User Request


Reset password



The Hexoskin system allows to upload data from TCX or FIT files.


Hexoskin allows to create studies in order to organize collected data, generate reports, create planning for study's subjects.

There are also preselected routines/prescription and measurement that are configured according to Hexoskin Licenses, so some metrics will be automatically linked to the study and reports. Please ask for more info.


There are 3 types of users whom can interact with the Study resource, as follow:

Study Owner

Study Admins

Study Subjects


Each study has a unique identifier (called UUID). The UUID is used as prefix in subject username. In other words, each subject's username begins with the study UUID he belongs to following by an underscore and finally its own id. Example : The subject with the ID sub001 belonging to the study test with the UUID test will have the username test_sub001

Study group

A subject belongs to a group or also commonly called cohort. A cohort is a group of people who share a defining characteristic, typically those who experienced common events, experiences or conditions in a given period.

Change subject's group

Although we expect most studies using Hexoskin garment are prospective (using the collection of new recorded data), studies can be retrospective. And thus, it is possible to assign a group to subject after its onboarding date and even after the end of the study.


{ "name": "Example 1", "event_schedule": { "resource_uri": "/api/activity/4/", "start_time": "09:00", "end_time": "10:00", "repeat_frequency": "P1M", "byMonthDay": [ 1, 15 ] }, "description": "A description here" }
{ "name": "Example", "event_schedule": { "start_time": "09:00", "repeat_frequency": "P10D", "resource_uri": "/api/trainingroutine/4/", "end_time": "10:00", "byPeriodDay": [2, 4] } }
{ "name": "Example", "event_schedule": { "resource_uri": "/api/activity/4/", "repeat_frequency": "P7D", "repeatCount": 2, "start_time": "09:00", "end_time": "10:00", } }
{ "name": "Example", "event_schedule": { "repeat_frequency": "P2D", "resource_uri": "/api/activity/4/", "end_date": "2021-01-12", "start_date": "2020-12-24", "repeatCount": 1 } }
{ "name": "Example", "event_schedule": { "start_date": "2020-12-24", "repeat_frequency": "P1D", "repeatCount": "10", “start_time": "09:00", “end_time": "10:00" }
{ "name": "Example", "event_schedule": { "start_date": "2020-12-24", "end_date": "2021-01-24" "repeat_frequency": "P2D", "byPeriodDay": [2] } }
{ "name": "Example", "event_schedule": { "repeat_frequency": "P1W", "by_week_day": [ 0, 1 ], "resource_uri": "/api/activity/4/", "repeatCount": 2 } }

In the context of studies, it is possible to create a planning. A planning allows to schedule :

The planning is described in a JSON format. It is stored in the property planning in study. The schema is mainly inspired by although there is some differences. Instead of using camel case styles, underscore style is prefered dans un soucis de consistance. The following table shows the different properties. Some examples on the right columns are shown.

Total Duration: The combination of repeat_count and repeat_frequency must result in a total duration that does not exceed 5 years. This constraint ensures that the planning remains within a reasonable timeframe for study purposes. For example, a repeat_frequency of "P1M" with a repeat_period of 60 (5 years) is acceptable, but a repeat_period of 61 would exceed the 5-year limit.

Property Type Example Description
repeat_frequency ISO_8601 notation P1M Defines the frequency at which Events will occur according to a schedule Schedule. The intervals between events should be defined as a Duration of time.. Based on ISO 8601 Duration (
repeat_period integer 2 Defines the number of times a period is repeated. If 0, the period is repeated until the study end.
days_offset integer 5 Specifies which day from subject's start date the schedule runs. If 0, the schedule starts the same day as start date.
resource_uri URI /api/trainingroutine/1012/ The unique URI where the object resides. It could be activitytype, trainingroutine, survey and kpi
start_time string 09:00 Start time of activity, trainingroutine. In the case of a survey, it must be answered after start time. This field is optionnal.
end_time string 16:00 End time of activity, trainingroutine. In the case of a survey, it must be answered before end time. This field is optionnal.
repeat_count integer 2 Defines the number of times a recurring the event will take place
by_month_day array of integer [1, 15] Defines the day(s) of the month on which a recurring Event takes place. Specified as an Integer between 1-31.
by_week_day array of integer [1, 2] Defines the day(s) of the week on which a recurring Event takes place. Specified as an Integer between 0-6. The week starts on Monday.
by_period_day array of integer [2] Defines the day(s) of the period on which a recurring Event takes place. Specified as an Integer between 1-N where N is the duration of the period defined by repeat_frequency.
start_date YYYY-MM-DD 2020-12-24 The start date and time of the item (in ISO 8601 date format).
end_date YYYY-MM-DD 2020-12-24 The end date and time of the item (in ISO 8601 date format).


{ "meta": { "total_count": 9 }, "objects": [ { "name": "Do 5 min Rest Test twice a day", "done": false, "event_schedule": { "date": "2020-07-14", "resource_uri": "/api/activitytype/4/" } }, { "name": "Do 5 min Rest Test twice a day", "done": false, "event_schedule": { "date": "2020-07-14", "resource_uri": "/api/activitytype/4/" } }, { "name": "Do 5 min Rest Test twice a day", "done": false, "event_schedule": { "date": "2020-07-15", "resource_uri": "/api/activitytype/4/" } }, { "name": "Do 5 min Rest Test twice a day", "done": false, "event_schedule": { "date": "2020-07-15", "resource_uri": "/api/activitytype/4/" } }, { "name": "Do 5 min Rest Test twice a day", "done": false, "event_schedule": { "date": "2020-07-16", "resource_uri": "/api/activitytype/4/" } }, { "name": "Do 5 min Rest Test twice a day", "done": false, "event_schedule": { "date": "2020-07-16", "resource_uri": "/api/activitytype/4/" } }, { "name": "Answer the survey every day", "done": false, "event_schedule": { "date": "2020-07-14", "resource_uri": "/api/survey/3/" } }, { "name": "Answer the survey every day", "done": false, "event_schedule": { "date": "2020-07-15", "resource_uri": "/api/survey/3/" } }, { "name": "Answer the survey every day", "done": false, "event_schedule": { "date": "2020-07-16", "resource_uri": "/api/survey/3/" } } ] }

In the context of studies, a calendar informs the subject when he has to :

The calendar is generated from the planning (described above) and the onboarding date (start_date) that may be different for each subject of a given study. The calendar is available through /api/calendar/. The properties done informs whether the event occured. The filter end allows to get all the scheduled events before a given date.


It is possible to create surveys in the context of studies. A survey is a set of questions that are asked to subjects in the studies. Creating a survey in a study will allow the administrator of the study to follow more closely the progress of the subjects on a particular topic of his choice. For example in the case of the COVID-19, a healthcare professionnal could have their patients fill a daily survey about the symptoms they are experiencing. The system can later on compile the answers and generate a report.

In order to use the surveys in a study, the following resources are available. Those resources allow to get surveys and post responses. Surveys should be created in the admin panel or OneView to be able to use them.

Get a survey


Submit a response to a survey


Post a response to a survey



Astroskin-specific resources

The Astroskin is a modified version of the Hexoskin that embeds a Pulse Oxymetry sensor, a 3-lead ECG, and a skin temperature sensor. More details available at



The PPG, or PhotoPlethysmoGram, is the raw photoplethysmograph sensor measurement.



PTT, or Pulse Transit Time, represents the transit time between the heart beat measured by the ECG electrodes and the heart beat measured from the forehead sensor. This value helps compute the Systolic pressure value.



SPO2 status


Systolic pressure




Temperature status


OAuth Endpoints

OAuth Client


OAuth2 Tokens


OAuth2 Endpoints

Miscellaneous Resources

Content Type




Release Notes


Bug Fixes


Bug Fixes






Bug Fixes


Bug Fixes


Bug Fixes


Bug Fixes









Bug Fixes



Bug Fixes




Bug Fixes








Bug fix



Bug fix


Bug fix


Bug fix







Bug fixes


Bug fixes


Bug fixes



Bug fixes



Bug fixes



Bug fixes