REST implementation

This section describes the aspects common to all REST-based interfaces of Cumulocity IoT. The interfaces are based on the Hypertext Transfer Protocol 1.1 using HTTPS.

HTTP usage

Authentication

All requests need to be authenticated. There are two ways to do that. First is
to include the HTTP “Authorization” header. The second is OAuth2 authentication code grant. Both are described below.

For the Authorization header method the format is:

Authorization: Basic <<Base64 encoded credentials>>

An example can be found in the Wikipedia entry.

For OAuth authentication the format is:

Authorization: Bearer <<Base64 encoded access token>>

Cumulocity IoT uses the URL in the “Host” header to determine the tenant to authenticate against. Alternatively, you can pass the tenant’s ID as part of the “Authorization” header in the following form:

<<tenant ID>>/<<user name>>:<<password>>

For details on the tenant ID, refer to Tenants > Tenant ID and tenant domain.

Cumulocity IoT supports two factor authentication. If it is enabled, the two factor authentication token is sent in header:

TFAToken:<<tfa-token>>

If the token expires and requires renewal, the backend sends a response header:

TFATokenExpired:TFATokenExpired

JWT token authentication

Cumulocity IoT supports JWT token authentication. The HTTP header must include:

Authorization: Bearer <<Base64 encoded JWT token>>

The JWT token must be signed using RSA signature with SHA-256 (RS256). The minimal RSA key size is 512 bit. You can generate an example key here.

You must upload your public key to the tenant options to the “token.publicKey” category.

Example:

POST /tenant/options
Host: ...
Authorization: Basic ...
Content-Type: application/vnd.com.nsn.cumulocity.option+json;ver=...
Accept: application/vnd.com.nsn.cumulocity.option+json;ver=...
{
    "category": "token.publicKey",
    "key": "myPubKey",
    "value": "..."
}

The “key” is an identifier of the public key, which will be referenced in the JWT token header, and the “value” is the public key in PEM format.

Now you can generate the JWT token and sign it with th ematching private key. For example you can do it here.

Token format:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "myPubKey"
}
{
  "iss": "cumulocity",
  "aud": "myTenant",
  "sub": "username",
  "nbf": 1515678716,
  "exp": 1516629116
}

If tenant/username don’t match or the token is expired or the signature is invalid then a 401 error will be returned.

OAuth authentication code grant

The login with OAuth requires a correct configuration on the Cumulocity IoT side. With the configuration, an additional button is available on the Login page. After clicking the button, the user is redirected to authenticate with the configured authorization server. On successful login, the user is redirected to Cumulocity IoT.

Authentication details are exchanged using cookies. There are two parts to it, the first is the authentication cookie that is handled automatically by the Cumulocity IoT platform. The second is the XSRF-TOKEN cookie. When a client receives the cookie, it should take the value and put it in the X-XSRF-TOKEN request header in all subsequent requests.

The flow of authenticating with OAuth authentication code grant is as follows:

Authentication flow

The first request executed by the browser is:

POST /tenant/loginOptions
Host: ...
Content-Type: application/vnd.com.nsn.cumulocity.loginOptionCollection+json;ver=...
Accept: application/vnd.com.nsn.cumulocity.loginOptionCollection+json;ver=...

Response:

{
    "loginOptions": [
        {
            "buttonName": "Login with oauth",
            "grantType": "AUTHORIZATION_CODE",
            "initRequest": "https://TENANT.cumulocity.com/tenant/oauth?response_type=code&tenant_id=TENANT",
            "self": "http://TENANT.cumulocity.com/tenant/loginOptions/oauth2",
            "type": "oauth2"
        },
        {
            "self": "http://dev-d.cumulocity.com/tenant/loginOptions/basic",
            "type": "basic"
        }
    ],
    "self": "http://dev-d.cumulocity.com/tenant/loginOptions/"
}

Here we have two login options, one with basic and the other with OAuth2. If a user decides to login with OAuth, the browser must invoke the request provided in the initRequest parameter.

The initRequest initiates the redirect, in which the user is prompted for credentials. After successful login, the user is redirected back to the browser, where it must capture the code request parameter. Then the request to exchange the code for the token is as follows:

POST /tenant/oauth?grant_type=authorization_code&code=<<code>>
Host: ...

A successful response will have no body but the following response headers:

Set-Cookie: authorization=<<token>>;
Set-Cookie: XSRF-TOKEN=<<xsrfToken>>;

Authorization cookie is valid for 2 weeks.

Application management

Cumulocity IoT uses a so-called “application key” to distinguish requests coming from devices and traffic from applications. If you write an application, pass the following header as part of all requests:

X-Cumulocity-Application-Key: <<application key>>

For example, if you registered your application in the Cumulocity IoT administration application with the key “myapp”, pass

X-Cumulocity-Application-Key: myapp

This makes your application subscribable and billable. If you implement a device, do not pass the key.

Make sure that you pass the key in all requests coming from an application. If you leave out the key, the request will be considered a device request and the corresponding device will be marked as “available”.

Limited HTTP clients

If you use an HTTP client that can only perform GET and POST methods in HTTP, you can emulate the other methods through an additional “X-HTTP-METHOD” header. Simply issue a POST request and add the header, specifying the actual REST method to be executed. For example, to emulate the “PUT” (modify) method, you can use:

POST ...
X-HTTP-METHOD: PUT

Processing mode

Every update request (PUT, POST, DELETE) executes with a so-called processing mode. The processing modes are as follows:

Processing mode Description
Persistent (default) All updates will be send both to the Cumulocity IoT database and to real-time processing.
Transient Updates will be sent only to real-time processing. As part of real-time processing, the user can decide case by case through scripts whether updates should be stored to the database or not.
Quiescent The QUIESCENT processing mode behave like the PERSISTENT processing mode with the exception that no real-time notifications will be sent. Currently, the QUIESCENT processing mode is applicable for measurements and events only.
CEP The CEP processing mode behaves like the TRANSIENT processing mode with the exception that no real-time notifications will be sent. Currently, the CEP processing mode is applicable for measurements and events only.

To explicitly control the processing mode of an update request, an “X-Cumulocity-Processing-Mode” header can be used with a value of either “PERSISTENT”, “TRANSIENT”, “QUIESCENT” or “CEP”:

X-Cumulocity-Processing-Mode: TRANSIENT

Authorization

All requests issued to Cumulocity IoT are subject to authorization. To determine the required permissions, see the “Required role” entries in the reference documentation for the individual requests. To learn more about the different permissions and the concept of ownership in Cumulocity IoT, see “Managing permissions and ownership” in the Section “Security aspects”.

Media types

Each type of data is associated with an own media type. The general format of media types is

application/vnd.com.nsn.cumulocity.<<type>>+json;ver=<<version>>;charset=UTF-8

Each media type contains a parameter “ver” indicating the version of the type. At the time of writing, the latest version is “0.9”. The complete media type names are given in the respective sections of the reference guide. As an example, the media type for an error message in the current version is

application/vnd.com.nsn.cumulocity.error+json;ver=0.9;charset=UTF-8

Media types are used in HTTP “Content-Type” and “Accept” headers. If you specify an “Accept” header in a POST or PUT request, the response will contain the newly created or updated object. If you do not specify the header, the response body will be empty.

If a media type without “ver” parameter is given, the oldest available version will be returned by the server. If the accept header contains the same media type in multiple versions the server will return a representation in the latest supported version.

Date format

Data exchanged with Cumulocity IoT in HTTP requests and responses is encoded in JSON format and UTF-8 character encoding. Timestamps and dates are accepted and emitted by Cumulocity IoT in ISO 8601 format:

Date: YYYY-MM-DD
Time: hh:mm:ss±hh:mm
Timestamp: YYYY-MM-DDThh:mm:ss±hh:mm

To avoid ambiguity, all times and timestamps must include timezone information. Please take into account that the plus character “+” must be encoded as “%2B”.

Cumulocity IoT API data types

Cumulocity IoT APIs are restricted by following data types:

Type Description Size Possible values
boolean true or false 1 bit true, false
int two’s complement integer 32 bit from -2,147,483,648 to +2,147,483,647
long two’s complement integer 64 bit from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
float IEEE 754 floating point 32 bit from 1.40129846432481707e-45 to 3.40282346638528860e+38 (positive or negative)
double IEEE 754 floating point 64 bit from 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative)
string represents character strings - maximum 2,147,483,647 characters
datetime date or time or timestamp - ISO 8601 datetime
object A structure of key and value pairs - JSON objects, refer to w3schools > JS JSON > JSON Objects
array A list of values that have the same type - JSON arrays, refer to w3schools > JS JSON > JSON Arrays

Error reporting

In error cases, Cumulocity IoT returns standard HTTP response codes as described in RFC2616. A Client should not only be able to handle individual codes but classes of codes as well (e.g., 4xx). The response body can contain more information about the error, see the error media type definition below. General error interpretations are:

Code Name Description
400 Bad Request The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
401 Unauthorized Authentication has failed, or credentials were required but not provided.
403 Forbidden You are not authorized to access the API.
404 Not Found Resource not found at given location.
405 Method not allowed The employed HTTP method cannot be used on this resource (e.g., using “POST” on a read-only resource).
409 Update Conflict Conflict on resource update, entity was changed in the meantime.
409 Duplicate The entity already exists in the data source.
413 Execution timeout, operation will be abandoned Query had been running too long and was timed out.
422 Invalid Data General error with entity data format.
422 Non Unique Result Resource constraints error. Non-unique result from the query.
422 Unprocessable entity Resource cannot be processed.
429 Requests rate exceeds the limit If the request rate limit per second is exceeded, the requests are delayed and kept in queue until the queue number limit is exceeded in which case the request is terminated with an error.
500 Internal Server Error An internal error in the software system has occurred and the request could not be processed.
503 Service Unavailable The service is currently not available. This may be caused by an overloaded instance or it is down for maintenance. Please try it again in a few minutes.

REST usage

Interpretation of HTTP verbs

The semantics described in the HTTP specification are used:

If a PUT request only contains parts of a resource, so called “fragments”, only those parts are updated. To remove a fragment, use a PUT request with a null value for the fragment. PUT cannot update sub-resources that are identified by a separate URI.

URI space and URI templates

Clients should not make assumptions on the layout of URIs used in requests, but construct URIs from previously returned URIs or URI templates. The root interface provides the entry point for clients, see below.

URI templates contain placeholders in curly braces, which need to be filled by the client to produce a URI. As an example, see the following excerpt from the event API response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.eventApi+json;...
Content-Length: ...

{
  ...
  "events" : { "self" : "http://..." },
  "eventsForSourceAndType" : "http://...?type={type}&source={source}"
  ...
}

The client would need to fill the “type” and “source” placeholders with the desired type and source devices of the events to be returned. The meaning of these placeholders is documented in the respective interface descriptions in the reference guide.

Interface structure

In general, Cumulocity IoT REST resources are modelled according to the following pattern:

Query result paging

Collection resources support paging of data to avoid passing huge data volumes in one block from client to server. GET requests to collections accept two query parameters: “pageSize” indicates how many entries of the collection should be returned. By default, 5 entries are returned. The upper limit for one page is currently 2,000 documents, any larger requested page size is trimmed to the upper limit. “currentPage” defines the slice of data to be returned, starting with “1”. By default, the first page is returned.

For convenience, collection resources provide a “next” and “prev” links to retrieve the next resp. the previous page of the results. This is an example response for managed object collections:

{
  "self" : "...",
  "managedObjects" : [
    ...
  ],
  "statistics" : {
    "totalPages" : 7,
    "pageSize" : 5,
    "currentPage" : 2
  },
  "prev" : "http://...?pageSize=5&Page=1",
  "next" : "http://...?pageSize=5&Page=3"
}

Please note that the totalPages property can be expensive to compute, hence it is not returned by default for range queries. To include totalPages in the result, add the query parameter “withTotalPages=true”.

Info: If inventory roles are applied to a user, a query by the user may return less than pageSize results even if there are more results in total.

Query result paging for users with restricted access

If a user does not have a global role for reading data from the API resource but rather has inventory roles for reading only particular documents there are some differences in query result paging:

The above behavior results from the fact that the querying mechanism is iterating maximally over 10 * max(pageSize, 100) documents per request and stops though the full page of data accessible for the user could not be collected. When the next page is requested the querying mechanism starts the iteration where it finished the previous time.

Query result by time interval

Use the following parameters to obtain data for the specified time interval:

Example formats:

dateTo=2019-04-20
dateTo=2019-04-20T08:30:00.000Z

Parameters are optional. Values provided with those parameters are inclusive.

Root interface

To discover the URIs to the various interfaces of Cumulocity IoT, a “root” interface is provided. This root interface aggregates all the underlying API resources and is available through http://<<yourURL>>.cumulocity.com/platform/". For more information on the different API resources, please consult the respective API sections of this reference guide.

Platform [application/vnd.com.nsn.cumulocity.platformApi+json]

Name Type Occurs Description
self URI 1 Link to this Resource
inventory InventoryAPI 1 See inventory interface.
identity IdentityAPI 1 See identity interface.
event EventAPI 1 See event interface.
measurement MeasurementAPI 1 See measurement interface.
audit AuditAPI 1 See auditing interface.
alarm AlarmAPI 1 See alarm interface.
user UserAPI 1 See user interface.
deviceControl DeviceControlAPI 1 See device control interface.

GET the Platform resource

Response body: application/vnd.com.nsn.cumulocity.platformApi+json

Example response:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.platformApi+json;...
Content-Length: ...

{
  "self" : "<<URL to the platform API resource>>",
  "event" : {
    "self" : "<<URL to the event API resource>>",
    "events" : { "self" : "<<URL to event collection resource>>" },
    "eventsForSourceAndType" : "<<URL to event collection resource>>?type={type}&source={source}"
    ...
  },
  "inventory" : {
    ...
  },
  ...
}

Generic media types

Error [application/vnd.com.nsn.cumulocity.error+json]

The error type provides further information on the reason of a failed request.

Name Type Occurs Description
error string 1 Error type formatted as “<<resource type>>/<<error name>>". For example, an object not found in the inventory is reported as “inventory/notFound”.
message string 1 Short text description of the error
info string 1 URL to an error description on the Internet.
details Error details 1 Error details. Only available in DEBUG mode.

Error details are provided in the following structure:

Name Type Occurs Description
expectionClass string 1 Class name of an exception that caused this error.
exceptionMessage string 1 Exception message content.
expectionStackTrace string 1 Strack trace of the exception.
- - - Further diagnostic information depending on error type.

PagingStatistics [application/vnd.com.nsn.cumulocity.pagingStatistics+json]

Paging statistics for collection resources are provided in the following format:

Name Type Occurs Description
totalPages int 1 The total number of paginated results (pages).
pageSize int 1 Maximum number of records contained in this query.
currentPage int 1 The current returned page within the full result set, starting at “1”.

Info: The totalPages property is not returned by default in the response. To include it, add the query parameter withTotalPages=true.