HTTPS Device API Overview

This is the HTTPS Device API for the Murano Platform.

The purpose of this API is to provide device software and firmware with the ability to communicate with Murano. Devices use this API to perform actions such as authentication, posting sensor and status data, and retrieving configuration and control updates.

When used in this document, "timestamp" is a unix timestamp, defined as the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970.

HTTPS Device APIs

Provisioning And OTA Updates

Writing And Reading Data

Misc

HTTP Responses

Typical HTTP response codes include:

Code Response Description
200 OK Successful request, returning requested values
204 No Content Successful request, nothing will be returned
4xx Client Error There was an error* with the request by the client
401 Unauthorized Missing or invalid credentials
5xx Server Error Unhandled server error. Contact support.

Note: Aliases that are not found are not considered errors in the request. See the documentation for post, get, and post/get for details.

Libraries and Sample Code

Sample code that uses this API can be found on the Murano Getting Started product examples:

Notational Conventions

This document uses the following notational conventions:

Product Domain

Each Murano Product is assigned a unique API domain for devices to connect to. In this document, we will use the example domain of "example.m2.exosite.io" as an example Product domain. Replace the example domain with the Endpoint shown in the associated Product page of your account UI.

NOTE: The Endpoint referenced above can also be retrieved via the murano device httpurl command. Read about Murano CLI for more information on the murano command.

TLS Connection Requirements

When making a secure TLS connection attempt to the API domain, it is required to specify the domain as the SNI field in the TLS connection request. The HTTP "Host" header must also be set to the domain name. Any mismatch or use of an invalid domain will result in the connection being terminated without response.

Authentication

A device may authenticate with either a TLS Client Certificate or by using a secret Token specified in the "X-Exosite-CIK" HTTP request header.

Murano Products can be configured to allow devices to provision their own identities or to allow only whitelisted device identities to be provisioned. This configuration option is available via the Product Settings tab as the Allow devices to register their own identity checkbox. When checked (default), any device using this API with the assigned Product Endpoint can provision themselves without the need to be whitelisted in advance. If this option is disabled (unchecked), then device identities must be whitelisted in advance in order to provision and communicate with the Product.

NOTE: When using a TLS Client Certificate for authentication, the certificate "Subject" CommonName (CN) must hold the connecting device's identity.

Provisioning and OTA updates

Provision

When a Product is configured for Token authentication, calling this endpoint will provision credentials for the given <identity> and return the secret <token> that the device must use for all subsequent API requests. Identities must also conform to the identity format specification defined in the Settings tab of the Product UI.

request

POST /provision/activate HTTP/1.1
Host: example.m2.exosite.io
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: <length>

id=<identity>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Keep-Alive
Content-Length: <length>
Content-Type: text/plain; charset=utf-8

<token>

Response may also be:

example

Provision identity 12345678

$ curl -i 'https://example.m2.exosite.io/provision/activate' \
    -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \
    -d 'id=12345678'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 40
Content-Type: text/plain; charset=utf-8

22596363b3de40b06f981fb85d82312e8c0ed511

List Available Content

List available content <content-id>s.

GET /provision/download HTTP/1.1
Host: example.m2.exosite.io
{X-Exosite-CIK: <token>}
<blank line>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Keep-Alive
Content-Length: <length>
Content-Type: text/csv; charset=utf-8

<content-id 1>
<content-id 2...>
<content-id n>

Response may also be:

example

$ curl -i 'https://example.m2.exosite.io/provision/download' \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 71
Content-Type: text/csv; charset=utf-8

MANIFEST
fw_20150519_rev01b.bin
fw_20160101_rev02.bin
splash01.png
splash02.png

Get Content Info

Retrieve meta information (content-type, size, updated timestamp, description) for the specified <content-id>.

GET /provision/download?id=<content-id>&info=true HTTP/1.1
Host: example.m2.exosite.io
{X-Exosite-CIK: <token>}
<blank line>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Keep-Alive
Content-Length: <length>
Content-Type: text/csv; charset=utf-8

<content-type>,<byte-size>,<updated-timestamp>,<description>

Response may also be:

example

$ curl -i 'https://example.m2.exosite.io/provision/download?id=splash01.png&info=true' \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 45
Content-Type: text/csv; charset=utf-8

image/png,23427,1462500951,Boot splash screen

Download Content

Download the content <content-id> in full or in part. To request chunks of the content, use the header Range: bytes=<range-specifier>. <range-specifier> takes the form of X-Y where both X and Y are optional but at least one of them must be present. X is the start byte position to return. Y is the end position. Both are 0 based. If X is omitted, Y will request the last Y count of bytes of the content. If Y is omitted, it will default to the end of the content. The response Content-Type header will be as defined in the content meta info.

GET /provision/download?id=<content-id> HTTP/1.1
Host: example.m2.exosite.io
{X-Exosite-CIK: <token>}
{Range: bytes=<range-specifier>}
<blank line>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Keep-Alive
Content-Length: <number of bytes being returned>
Content-Type: <content-type>
{Accept-Ranges: bytes}
{Content-Range: bytes <first position>-<last position>/<total length>}

<blob>

Response may also be:

example

Download entire file

$ curl -i 'https://example.m2.exosite.io/provision/download?id=splash01.png' \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 23427
Content-Type: image/png

<23427-byte-blob>

Download first 1024 bytes of the file

$ curl -i -r 0-1023 https://example.m2.exosite.io/provision/download?id=splash01.png \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 1024
Content-Type: image/png
Accept-Ranges: bytes
Content-Range: bytes 0-1023/23427

<1024-byte-blob>

Writing And Reading Data

Write

Write one or more resources identified by <alias> with the given <value>. The connecting device is identified and authenticated with the provided <token>. If the Murano Product has defined resources with matching <alias>es, the <value>s are stored as the device state at timestamp the data was received by Murano. If multiple aliases are specified, they are written at the same timestamp. This method generates an event type of "data_in" on the Murano Device2 service and may be used to, for instance, store the data in the Tsdb database or alert users or other services of the event.

request

POST /onep:v1/stack/alias HTTP/1.1 
Host: example.m2.exosite.io 
X-Exosite-CIK: <token>
Content-Type: application/x-www-form-urlencoded; charset=utf-8 
Content-Length: <length> 
<blank line>
<alias 1>=<value 1>&<alias 2...>=<value 2...>&<alias n>=<value n>

response

HTTP/1.1 204 No Content 
Date: <date> 
Server: Murano
Connection: Keep-Alive
<blank line>

example

$ curl -i 'https://example.m2.exosite.io/onep:v1/stack/alias' \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511' \
    -d 'temperature=63'
HTTP/1.1 204 No Content
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive

Read

Read the most recent value from one or more resources. If at least one <alias> resource definition exists, the set value will be returned.

Read the most recent value from one or more resources with <alias>. The client (e.g., device or portal) to read from is identified by <CIK>. If at least one <alias> is found and has data, data will be returned.

request

GET /onep:v1/stack/alias?<alias 1>&<alias 2...>&<alias n> HTTP/1.1
Host: example.m2.exosite.io
{X-Exosite-CIK: <token>}
Accept: application/x-www-form-urlencoded; charset=utf-8
<blank line>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Close
Content-Length: <length>
<blank line>
<alias 1>=<value 1>&<alias 2...>=<value 2...>&<alias n>=<value n>

example

$ curl -i 'https://example.m2.exosite.io/onep:v1/stack/alias?thermostat' \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511' \
    -H 'Accept: application/x-www-form-urlencoded; charset=utf-8'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 13
Content-Type: application/x-www-form-urlencoded; charset=utf-8

thermostat=65

Hybrid Read Write

Write one or more values with <alias w> with given <value> and also read the most recent values from <alias r>.

Note: All writes occur before all reads.

request

POST /onep:v1/stack/alias?<alias r1>&<alias r2...>&<alias rn> HTTP/1.1
Host: example.m2.exosite.io
{X-Exosite-CIK: <token>}
Accept: application/x-www-form-urlencoded; charset=utf-8
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: <length>
<blank line>
<alias w1>=<value 1>&<alias w2...>=<value 2...>&<alias wn>=<value n>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Close
Content-Length: <length>
<blank line>
<alias r1>=<value 1>&<alias r2...>=<value 2...>&<alias rn>=<value n>

example

$ curl https://example.m2.exosite.io/onep:v1/stack/alias?thermostat \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511' \
    -H 'Accept: application/x-www-form-urlencoded; charset=utf-8' \
    -d 'temperature=63'
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 13
Content-Type: application/x-www-form-urlencoded; charset=utf-8

thermostat=65

Long Polling

The read endpoint also supports long polling. Long polling is a method of getting a server push without the complexities of setting up publicly accessible HTTP server endpoints on your device. As the name suggests, long polling is similar to normal polling of an HTTP resource, but instead of requiring the client to make a new request to the server constantly, the server will wait to return until it has new information to return to the client (or a timeout has been reached).

To perform a request with long polling, simply add the header Request-Timeout: <miliseconds> to your request. The server will then wait until a new datapoint is written to the given resource and will then immediately return the value. If no datapoint is written before that time, a 304 Not Modified is returned and the client may make another long polling request to continue monitoring that resource.

You may also optionally add an If-Modified-Since header to specify a start time to wait. This is exactly the same as the alias.last semantics in scripting. You will want to use this if it's important that you receive all updates to a given resource; otherwise it is possible to miss points written between long polling requests.

Note: Only one resource may be read at a time when using long polling.

request

GET /onep:v1/stack/alias?<alias 1> HTTP/1.1
Host: example.m2.exosite.io
{X-Exosite-CIK: <token>}
Accept: application/x-www-form-urlencoded; charset=utf-8
Request-Timeout: <timeout>
If-Modified-Since: <timestamp>
<blank line>

response

When the device set state is updated:

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Close
Content-Length: <length>
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Last-Modified: <value-set-date>
<blank line>
<alias>=<value>

If the device state is not updated before timeout:

HTTP/1.1 304 Not Modified
Date: <date>
Server: Murano
Connection: Close
Content-Length: <length>
<blank line>

When the resource is written and a value is returned, a Last-Modified header is included. When it is vital for your application to receive all updates to a resource, you can pass the Last-Modified header value back as the If-Not-Modified-Since header in your next request to make sure you do not miss any points that may have been written since the last request returned.

example

$ curl https://example.m2.exosite.io/onep:v1/stack/alias?thermostat \
    -H 'X-Exosite-CIK: 22596363b3de40b06f981fb85d82312e8c0ed511' \
    -H 'Accept: application/x-www-form-urlencoded; charset=utf-8'
    -H 'Request-Timeout: 30000
    -H 'If-Modified-Since: 1408088308
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 13
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Last-Modified: 1408088412

thermostat=65

Record

Report data to one or more historical timestamps of one or more aliases. The connecting device is identified and authenticated with the provided <token>. Timestamps to the same alias cannot have less than one-second differences between each other, doing so results in error in response.

request

This example records to <alias 1> in <timestamp 1> and <timestamp 2>, and records to <alias 2> in <timestamp 3> and <timestamp 4>.

POST /onep:v1/stack/record HTTP/1.1
Host: example.m2.exosite.io
X-Exosite-CIK: <token>
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: <length>
<blank line>
alias=<alias 1>&<timestamp 1>=<value 1>&<timestamp 2>=<value 2>&alias=<alias 2>&<timestamp 3>=<value 3>&<timestamp 4>=<value 4>

response

HTTP/1.1 204 No Content 
Date: <date> 
Server: <server> 
Connection: Close 
Content-Length: 0 
<blank line>
HTTP/1.1 409 Conflict
Date: <date>
Server: <server>
Connection: Close
Content-Length: <length>
<alias 1>=<timestamp 1>&<alias 2>=<timestamp 3>

example

Report two values to temperature and three to state.

$ curl https://example.m2.exosite.io/onep:v1/stack/record \
    -H 'X-Exosite-CIK: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \
    -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \
    -d 'alias=temperature&1506708552=23&1506708551=22&alias=state&1506708552=on&1506708551=off&1506708550=on'

Misc

Timestamp

Get the current time according to the server.

request

GET /timestamp HTTP/1.1
Host: example.m2.exosite.io
<blank line>

response

HTTP/1.1 200 OK
Date: <date>
Server: Murano
Connection: Keep-Alive
Content-Length: <length>
Content-Type: text/plain; charset=utf-8

<timestamp>

example

$ curl -i https://example.m2.exosite.io/timestamp
HTTP/1.1 200 OK
Date: Fri, 05 May 2017 00:11:22 GMT
Server: Murano
Connection: Keep-Alive
Content-Length: 10
Content-Type: text/plain; charset=utf-8

1408088308