A Timeseries is a time-order collection of data points from one or more sensors. Data points contain:

  • a value
  • a port that distinguishes the type and shape of that value
  • a timestamp when the reading was taken by the sensor, and
  • a “created” timestamp when the reading was recorded by the Helium Platform

Timeseries data can be retrieved for a particular sensor or the organization Because individual data points are immutable, their contained values appear in the attributes section, rather than the meta section as do mutable objects.


Each data point received on the Helium network is associated with a text value known as its port. A port identifies the type and format of the data point’s value field.

For example, the built-in port "t" identifies temperature readings, and the "d" port distinguishes door readings—in essence, a port is a tag that uniquely identifies the “shape” of a reading, and thereby lets you interpret its meaning. We’ve reserved the following port names to describe the Helium sensing platform:

Port Description Value type
t Temperature reading (degrees Celsius) number
d Door sensor reading: 0 means “opening” and 1 means “closing”. If polling is enabled, 2 means “currently open”, and 3 means “currently closed”. number from 0 to 3
b Battery level (millivolts) number
p Atmospheric pressure (pascals) number
h Humidity (percentage) number
l Light (percentage) number
m Motion detected boolean
_e Helium network event object
_se Sensor event object


Avoid using port names that start with an underscore “_”. In order to avoid name collisions with ports that Helium uses, we recommend avoiding port names that start with the “_” character.

You are not limited to these ports—when you push data to an organization or sensor’s timeseries, you can specify any port (and any value) you wish. We’ve chosen to keep our reserved identifiers short; however, you may wish to use longer names for the sake of clarity.

When you retrieve information about a given sensor, all the ports associated with that sensor’s readings will be aggregated and returned in a ports field in the JSONAPI metadata.


Helium network events are recorded with the _e port. The value field contains an object with the following three fields:

  • kind: a short, unique identifier for this type of event. We recommend using reverse-DNS style identifiers — com.weyland-yutani.xenomorph, for example — so as to avoid name collisions.
  • details: an object containing type-specific keys and values describing the particulars of this event.
  • message: a human-readable string describing the event.

The following is an example JSON dump from an event generated by a sensor connecting to the network:

    "kind": "_sensor.connect",
    "details": {
        "card": {
            "variant": 255,
            "id": 5
        "pan-id": 61961,
        "mac": "6081f9fffe0007fa",
        "board-type": 1,
        "channel": 11,
        "versions": {
            "atom": "2050900",
            "sensor-config": "4b90039b34373ad2",
            "sensor-library": "d0a5d98a434729a3",
            "sensor": "4020100"
        "radio": 0,
        "element-mac": "6081f9fffe0001f0",
        "security": "sha204 key",
        "short-address": 44496
    "message": "Sensor 6081f9fffe0007fa connected via element 6081f9fffe0001f0 with PanID 61961, ShortAddr 44496, using Radio 0, on Channel 11 using sha204 key security."


Timeseries data can be filtered by port or by timestamp.

Adding filter[port]=temp,humidity will only return readings whose port value is one of temp, or humidity.

Timeseries can also be filtered by timestamp, using filter[start], and filter[end]. These can be used in conjunction with other filters (filter[port]), as well as page[size], and page[id]. The parameter to filter[start] and filter[end] is an ISO8601 -formatted timestamp, in UTC (ex. 2016-04-07T19:12:06.125Z).

filter[start] is inclusive, and filter[end] is exclusive. This is optimized for asking for a particular human-meaningful time-slice, like “January 2016”. To get all readings (paginated, like usual), you would request filter[start]=2016-01-01&filter[end]=2016-02-01.

Timestamps are accepted in one of two forms:


The last format may include a fractional seconds component. Examples of valid timestamps are as follows:

  • 2016-05-05
  • 2016-04-07T19:12:06Z
  • 2016-04-07T19:12:06.15Z
  • 2016-04-07T00:00:00Z

All times will be interpreted as UTC. No offset may be given.

All pagination links will continue to respect filter conditions.

Name Type Description
page[id] string ID of data point at which to start timeseries. Used in paging through the timeseries.
page[size] integer Number of data points to provide in response. (default: 1000, maximum: 10,000)
filter[port] array of strings Optional list of port names by which to filter the results.
filter[start] datetime Only return readings taken after this start date, inclusive.
filter[end] datetime Only return readings taken before this end date, exclusive.


Timeseries support aggregating data. This is useful for reporting and charting, where you might only be interested in a summary of data. Aggregations group data into buckets, based on time. For each bucket, some calculation is performed. For example, an aggregation might find the minimum temperature, calculated per calendar date.

Aggregations have two properties, a list of type, and a size.

Aggregation type is one of:

  • min
  • max
  • avg

Multiple aggregation types can be requested at once. To specify an aggregation type, use the agg[type]= query parameter. A single aggregation is specified like agg[type]=min, and multiple aggregations can be specified, separated by comma: agg[type]=min,max,avg.

The aggregation size specifies the time-frame a bucket spans. Valid aggregation sizes are:

  • 1m
  • 2m
  • 5m
  • 10m
  • 30m
  • 1h
  • 6h
  • 12h
  • 1d

Where m is minute, h is hour, and d is day. For 1m, 1h, and 1d, the 1 is optional. Data points always round down to the nearest bucket. For example:

  • 2016-05-11T19:47:57.Z with a size of 1d (one day) groups to 2016-05-11T00:00:00Z
  • 2016-05-11T19:47:57.Z with a size of 2m (two minutes) groups to 2016-05-11T19:46:00Z

Aggregation data-points differ from their source data points in a few days. The timestamp attribute will be set to the bucket for which this aggregation was calculated. The port will be the original port, wrapped in agg(), so a port of temp would become agg(temp). The value of the data point will be a json map, with one key and value for each calculation requested. An example aggregate data point:

    "attributes": {
        "port": "agg(b)",
        "timestamp": "2016-05-10T00:00:00Z",
        "value": {
            "avg": 2603.84972677596,
            "max": 2627,
            "min": 2417
    "id": "f0e36cac-a87f-4388-9ce4-102b3f01822a",
    "meta": {
        "created": "2016-05-10T20:26:25.165127Z"
    "relationships": {
        "sensor": {
            "data": {
                "id": "c24f3bdc-b668-4999-bb45-5ea11027a860",
                "type": "sensor"
    "type": "data-point"


The following query requests the two most recent entries in a given sensor’s timeseries. Please note that the brackets in the query string must be escaped.

curl -v -XGET -H 'Authorization: $YOUR_API_TOKEN' \

And the following query posts a new data point to this timeseries:

curl -i -H 'Content-Type: application/json' -H 'Authorization: $YOUR_API_TOKEN' \
     -XPOST 'https://api.helium.com/v1/sensor/$SENSOR_UUID/timeseries' -d '{
    "data": {
        "attributes" : {
            "port" : "wu-tang",
            "value" : "killer bees",
            "timestamp" : "2016-03-09T22:04:38Z"
        "type": "data-point"