API Reference Guide

Overview

The Vantiq API provides access to the Vantiq Automation Services in a programmatic fashion. The core concepts of the API are:

In this document we start by presenting the general resource model and the operations that all resources support. We then present the two main implementations of the API – the first is a REST implementation where resource instances are represented as URIs and operations are mapped to HTTP verbs. The second is a message based binding where JSON formatted messages are transmitted via WebSockets.

Vantiq also provides several SDK’s which express the API in various languages such as Java or Python (these SDKs are essentially covers over the 2 bindings presented here, designed to make it easier for programmers familiar with a specific language to use).

Accessing the API

The Vanitq Automation Server is a cloud-based system, so in most cases use of the API means interacting with a remote system over the Internet. To use the API you must know which Vantiq server you are accessing, you must be provisioned for access to that server, and you must authenticate your identity to the server so it knows which resources/resource instances you should have access to.

Service Endpoints

The Vantiq API is accessible through specific service endpoints:

The remainder of this document assumes a developer endpoint, https://dev.vantiq.com.

Provisioning

A customer may request Vantiq to provision access to either the cloud developer or production system. Vantiq will provision an organization with an initial namespace and organization administrator account. The credentials for the organization administrator will be provided to the customer’s authorized contact. Using these credentials the customer can self-provision additional namespaces and associated user accounts, subject to licensing constraints.

Each newly created namespace must be assigned a globally unique name (across all organizations). Given this we recommend the use of an organization specific prefix when creating namespaces.

In order to create a new user, a valid email address must be supplied to act as the username and an initial password must be supplied. The provisioned user may change their password at any time.

Authentication

Vantiq resources are secure and the requesting client must authenticate before issuing requests against the services. Authentication is performed via the following HTTP request:

 GET https://dev.vantiq.com/authenticate

The request must include an Authorization HTTP header containing standard HTTP basic authentication credentials consisting:

Authorization: Basic <encoded credentials>

The <encoded credentials> are created by Base64 encoding the concatenation of the username and password with a colon separator (i.e. username:password).

Upon successful authentication, a JSON object is returned that includes an access token. This access token is valid for 24 hours from the authentication request and must accompany each subsequent HTTP API request. The preferred mechanism for providing the token is via the Authorization header, using the Bearer realm:

Authorization: Bearer <access token>

The token can also be provided on the request URI via the token URI parameter:

GET https://dev.vantiq.com/docs/rcs/image/3F00D4D1-C2CB-45BF-A976-3C9C553C8651.png?token=<access token>

This approach is most often used to provide access to a 3rd party application or system that can only consume URIs and cannot set the HTTP header.

The access token identifies the caller and authorizes the request. Therefore, the token should be kept confidential by the client to which it was issued. When the access token expires, the caller must re-authenticate to retrieve a new token.

In addition to short term, user specific tokens, authentication can be performed using long lived access tokens. These tokens typically represent a specific application or 3rd party system that has been granted access to Vantiq for some purpose. For more details see the Tokens section of the Resource Reference Guide.

Tokens may also be

API Resource Types

The API provides access to both the system resources provided by the Vantiq server and to custom resources defined and deployed as part of a Vantiq “smart system”. Details on the Vantiq system resources can be found in the Resource Reference Guide. The details for any custom resources are obviously outside the scope of this documentation; however, in general any type which is defined in a namespace will appears as a custom resource to users with access to that namespace.

API Operations

Resources can be acted upon using the operations described in this section.

Examples of the use of these operations are contained in the upcoming REST API Examples and WebSockets API Examples sections. Some of the system types also support type-specific operations, which are described in the Resource Reference Guide

SELECT

The SELECT operation performs a query to retrieve matching instances of a given resource type. SELECT supports the following parameters:

Parameter Type Description Example
where JSON Object Criteria used to filter the results (see where parameter) where={ "age":{"$gt":10}}
sort JSON Object Order in which the results are returned (see sort parameter) sort={"lastName":-1}
props JSON Array List of the properties that should be included in each resource record (see props parameter) props=["firstName","lastName"]
page Integer Page of results to return, starting with 1 page=2
limit Integer Number of results to return in a single page limit=10
count “true” If set to true, the “X-Total-Count” HTTP header is also returned with the result set count count=true

INSERT

The INSERT operation creates one ore more new instances of a given resource type. INSERT supports the following parameters:

Parameter Type Description Example
count “true” If set to true, the “X-Total-Count” HTTP header is also returned with number of instances inserted count=true

UPDATE

The UPDATE operation updates a single preexisting instance of a given resource type. The instance must be identified either using its resource id.

UPSERT

The UPSERT operation either creates a new instance or updates an existing instance of a given resource type. The instance to be inserted/updated must be identified by its resource id.

DELETE

The DELETE operation removes existing instances of a given resource type. DELETE supports the following parameters:

Parameter Type Description Example
where JSON Object Criteria used to identify which instances to remove (see where parameter) where={ "value":{"$gt":10}}
count “true” If set to true, the “X-Total-Count” HTTP header is also returned with the number of instances deleted count=true

PATCH

The PATCH operation performs operations on an identified resource instance according to a modification commands defined in JSON Patch.

AGGREGATE

The AGGREGATE operation executes an aggregation pipeline involving the specified resource. AGGREGATE supports the following parameters:

Parameter Type Description Example
pipeline JSON Array The aggregate pipeline defined in the aggregate pipeline format. The pipeline parameter is only supported for the REST API via HTTP. When using the WebSockets API, simply specify the aggregate pipeline JSON object without the pipeline property. pipeline=[{"$match": {}}]

Standard Operation Parameters

where Parameter

SELECT and DELETE accept a where parameter which is a JSON object used to filter retrieved objects (SELECT) or delete objects according to the filter (DELETE). The where parameter accepts the following operators:

Operator Symbol Example
Equals { prop: 42 }
Greater Than $gt { prop: { "$gt": 42 } }
Greater Than or Equal $gte { prop: { "$gte": 42 } }
Less Than $lt { prop: { "$lt": 42 } }
Less Than or Equal $lte { prop: { "$lte": 42 } }
Not Equal $ne { prop: { "$ne": 42 } }
Match one in list $in { prop: { "$in": [ 13, 26, 42 ] } }
Match all in list $all { prop: { "$all": [ 13, 26, 42 ] } }
Do not match any in list $nin { prop: { "$nin": [ 13, 26, 42 ] } }
Match on all operators $elemMatch { prop: { "$elemMatch": { "$gt": 13, "$lt": 26 } } }
Regular Expression $regex { prop: { "$regex": "acme.*comp" } }
Match on array size $size { prop: { "$size": 10 } }

Operators can be combined using the following compound operators:

Logical AND ($and)

A logical AND operation uses the $and operator, e.g.,

{
    "$and": [
        { prop1: 10 },
        { prop2: { "$gt": 5 } }
    ]
}
Logical OR ($or)

A logical OR operation uses the $or operator, e.g.,

{
    "$or": [
        { prop1: 10 },
        { prop2: { "$gt": 5 } }
    ]
}
Logical NOT ($not)

A logical NOT operation uses the $not operator, e.g.,

{
    prop: { "$not": { "$gt": 5 } }
}
Logical NOR ($nor)

A logical NOR operation is one that does not satify any of the given expressions. The logical NOR uses the $nor operator, e.g.,

{
    "$nor": [
        { prop1: { "$gt": 42 } },
        { prop2: { "$eq": "abc" } }
    ]
}
GeoJSON

For GeoJSON data types, the following operators are supported:

Intersection ($geoIntersects)

To determine if the given location intersects with a given shape, use the $geoIntersects operator. E.g,

{ 
    prop: { 
        "$geoIntersects": { 
            "$geometry": { 
                type:        "Polygon", 
                coordinates: [ [0,0], [1,0], [1,1], [0,1] ]
            }
        }
    }
}
Within ($geoWithin)

To determine if the given location resides within a given shape, use the $geoWithin operator. E.g.,

{ 
    prop: { 
        "$geoWithin": { 
            "$geometry": { 
                type:        "Polygon", 
                coordinates: [ [0,0], [1,0], [1,1], [0,1] ]
            }
        }
    }
}
Proximity ($near and $nearSphere)

To determine if the given location is a given distance away from a given point, use the $near operator. E.g.,

{ 
    prop: { 
        "$near": { 
            "$geometry": { 
                type:        "Point", 
                coordinates: [ 13, 42 ]
            },
            "$maxDistance": 4,
            "$minDistance": 3
        }
    }
}

To perform a proximity search using spherical geometry, use the $nearSphere operators. E.g.,

{ 
    prop: { 
        "$nearSphere": { 
            "$geometry": { 
                type:        "Point", 
                coordinates: [ 13, 42 ]
            },
            "$maxDistance": 4,
            "$minDistance": 3
        }
    }
}

props Parameter

In the SELECT operation, the props parameter defines the list of properties to return within each resource instance. The props parameter should be a JSON array where each element is the name of the desired property to include. The following props parameter requests that the SELECT operation only return the name, ts, and value properties in each resource instance returned.

[ "name", "ts", "value" ]

sort Parameter

In the SELECT operation, the sort parameter defines the order of the results. The sort parameter is a JSON object where the property indicates the field to sort on and the value indicates if the sort is ascending or descending. A value of 1 means ascending order and -1 means descending order. For example, the following requests to sort the results by the name field in descending order:

{
    "name": -1
}

API Responses

Every response to an API request contains Response Code, Parameters, and the Response Body. Due to the differences in the transport of HTTP REST and WebSocket, the components of the response may be communicated differently.

Response Code

The API uses the HTTP response code regardless of the transport. The HTTP status codes are divided into the following classes of responses:

The following are the supported specific responses

Codes Type Reason
200 Success Success with a response body provided
204 Success Success with no response body provided
400 Client Failure Invalid request, usually indicating the request body is incorrectly formatted
401 Client Failure The requester has not been authorized or the access token has expired
403 Client Failure The requester is authorized but forbidden to access the requested resource
404 Client Failure The requested resource cannot be found or the requester is forbidden to access the requested resource
405 Client Failure The request used an HTTP verb that is not accepted by the requested resource
409 Client Failure The resource create or update request cannot be completed due to a uniqueness constraint
429 Client Failure The request cannot be completed due to a lack of resources or because a quota assigned to the requester
500 Server Failure The server encountered an unexpected condition which the API user should report to Vantiq support

Some of the operations support processing of more than one resource instance in a single request (INSERT, for example). The Vantiq server does not treat these as a single atomic request (or transaction), so it is possible for the operation to succeed for some of the instances and fail for others. In this case, the response produced will have the following characteristics:

Parameters

Parameters provide additional data relating to the requested operation. For example, if the operation requested a count, that information is returned as a parameter.

REST over HTTP

When using the API with REST over HTTP, the parameters are issued as normal HTTP headers. Currently, there are two supported parameters:

WebSockets

When using the API with WebSockets, the parameters in the response are issued in the response body.

Response Body

The body of the response will contain any returned data associated with the requested operation. Typically, the body will be transported in JSON format, either a single document or array of documents. In the case of a successful operation, it will return any data requested. In the case of a failure, it will communicate the details of any errors.

Error Body

If an error occurs during the requested operation, Vantiq will return an array of JSON documents containing the details of each of the failures. Each error document contains the following:

Property Type Description
code String A unique identifier for the error.
message String A human readable message that describes the details of the error.
params JSON Array A list of values related to the error and used to construct the error message.

API Bindings

REST Over HTTP Binding

Vantiq supports REST-based access to the resources using the following resource URI structure:

/api/v<version>/resources/[custom/]<resource name>[/<resource identifier>]

The current version of the API is 1, (i.e. /api/v1/...).

The optional /custom sub-path is included when accessing custom resources that correspond to user defined types. It is not used when accessing Vantiq system resources.

The <resource name> can be one of the Vantiq resources defined in the Resource Reference Guide or can be the name of a user-defined data type.

For some operations, the <resource identifier> is needed to uniquely identify a specific instance of a resource. For example, the users endpoint refers to a user resource type, which has a property username defined as natural key. The URI:

/api/v1/resources/users

refers to all user instances whereas:

/api/v1/resources/users/joe

refers to a specific user, joe.

API operations are issued to the HTTP REST API by mapping them to the HTTP methods. The following table describes all the supported operations and their corresponding HTTP structure:

Operation URL Path Query Params Method Description
SELECT /api/v#/resources/[custom/]<name> where, props, sort, count, page, limit GET Returns all matching resource instances of type <name>.
SELECT /api/v#/resources/[custom/]<name>/<id> GET Returns a single instance of the resource of type <name> identified by <id>.
INSERT /api/v#/resources/[custom/]<name> count POST Inserts a new instance of resources of type <name>
UPDATE /api/v#/resources/[custom/]<name>/<id> PUT Updates an existing instance of resources of type <name> identified by <id>
UPSERT /api/v#/resources/[custom/]<name>?upsert=true POST Upserts a new instance of resources of type <name>
DELETE /api/v#/resources/[custom/]<name> count DELETE Removes all matching resources of type <name>.
DELETE /api/v#/resources/[custom/]<name>/<id> DELETE Removes the resource instance of type <name> identified by <id>
PATCH /api/v#/resources/[custom/]<name>/<id> PATCH Patches the resource instance of type <name> identified by <id>
AGGREGATE /api/v#/resources/[custom/]<name>/aggregate pipeline GET Executes a given aggregate pipeline for the resource of type <name>
AGGREGATE /api/v#/resources/[custom/]<name>/aggregate POST Executes a given aggregate pipeline for the resource of type <name> where the requested pipeline is provided in the request body as a JSON document.

The following are type specific operations that are supported by the HTTP REST API:

Operation URL Path Query Params Method Description
PUBLISH /api/v#/resources/<name>/<id> POST Publishes the JSON payload in the request body. Only topics and sources support the publish operation.
EXECUTE /api/v#/resources/procedures/<id> POST Executes the specified procedure and returns the results. The arguments to the procedure are provided as either a JSON array (positional arguments) or a JSON document (named arguments).
QUERY /api/v#/resources/sources/<id>/query POST Performs a query against the specified source. The parameters for the query are provided in the request body as a JSON document.

Examples Using REST Over HTTP

The following examples refer to a user-defined TempByZip type, which is assumed to have three properties:

When referencing specific resources, the resource’s _id property, which is automatically assigned by Vantiq when a resource is created must be used. In the examples, 5696c2511de9a702175aadbb is used as an example _id.

Objective: Retrieve a list of all user-created and system-defined database types.

Method: GET
URL: /api/v1/resources/types

Objective: Insert a new weather reading object of the TempByZip type.

Method: POST
URL: /api/v1/resources/custom/TempByZip
Body: { "temperature": 32, "zipCode": 96160, "timeZone": "Pacific" }

Objective: Update an existing weather reading object of the TempByZip type.

Method: PUT
URL: /api/v1/resources/custom/TempByZip/5696c2511de9a702175aadbb
Body: { "temperature": 90, "zipCode": 96160, "timeZone": "Pacific" }

Objective: Insert or update a weather reading object of the TempByZip type, depending on whether the ZIP Code already exists.

Method: POST
URL: /api/v1/resources/custom/TempByZip?upsert=true
Body: { "temperature": 32, "zipCode": 95389, "timeZone": "Pacific" }

Objective: Delete all the TempByZip objects associated with particular time zone.

Method: DELETE
URL: /api/v1/resource/custom/TempByZip?where={"timeZone":"Pacific"}

Objective: Replace the temperature value with 100 in a specific TempByZip object.

Method: PATCH
URL: /api/v1/resource/custom/TempByZip/5696c2511de9a702175aadbb
Body: [ { "op": "replace", "path": "/temperature", "value": 100 } ]

Objective: Retrieve all TempByZip objects with temperatures below 32:

Method: GET
URL: /api/v1/resource/custom/TempByZip/aggregate?pipeline=[{"$match":{"temperature":{"$lt":32}}}]

WebSockets API

Vantiq support WebSocket access to the published resources. A WebSocket connection is created by connecting to the URL:

 wss://dev.vantiq.com/api/v<version>/wsock/websocket

The current version of the API is 1, (i.e. wss://dev.vantiq.com/api/v1/wsock/websocket)

Before a WebSocket connection can accept requests, the client must establish an authenticated session. Once established, this session is bound for the life of the connection and all requests made over that connection use the previously established identity. When the socket is closed, the session associated session is destroyed.

To establish a session using user credentials, the client must issue an authenticate request by sending a request document with the following properties:

For example, to authenticate the user joe with password joe#!&^, the client would send the following authentication request:

{
    "op": "authenticate",
    "resourceName": "users",
    "object": { "username": "joe", "password": "joe#!&^" }
}

To establish a session using an existing access token, the client must issue a validate request by sending a request document with the following properties:

For example,

{
    "op": "validate",
    "resourceName": "users",
    "object": "5696c2511de9a702175aadbb"
}

It may be necessary to retry either the authenticate or the validate operation at 100ms intervals since these operations are not guaranteed delivery to the server. The server responds to these operations with a JSON object containing a status field, which will carry the HTTP status of the operation. Usually the return status will be 200, which indicates a successful token authentication.

Data returned from the server will be in BLOB (Binary Large OBject) format which must be converted to JSON. For example, if a TypeScript/JavaScript app is using WebSockets, then the following example shows how to receive response BLOBs:

// the WebSocket has received a message from the server
 private wsonmessage(evt:MessageEvent) {
   // the server returns a Blob in evt.data (rather than text)
   var blobReader:FileReader = new FileReader();
   var wsThis = this;
   blobReader.addEventListener("loadend", function() {
     wsThis.processMessage(wsThis.abToString(blobReader.result));
   });
   blobReader.readAsArrayBuffer(evt.data);
 }

The preceding example requires two callbacks, one to convert the BLOB to a string and the second to process the contents of the string into JSON:

private abToString(ab:ArrayBuffer) {
  var binaryString:string = '';
  var bytes:Uint8Array = new Uint8Array(ab);
  var length:number = bytes.length;
  for (var i = 0; i < length; i++) {
    binaryString += String.fromCharCode(bytes[i]);
  }
  return binaryString;
}
private processMessage(msg:string) {
  var evtObject:Object = JSON.parse(msg);
  if (evtObject["status"] == 200) {
    // we've gotten a good response from the server
    // evtObject["body"] contains the response data
    // evtObject["errors"] contains any errors associated with the request
  }
}

Once authenticated, the operations defined in this document may be issued via the WebSocket session. To issue an request, the message sent to the WebSocket may contain the following properties:

Name Type Required Description
op String Yes The desired operation
resourceName String Yes The type of the resource
resourceId String Depends on op The unique identifier of the resource instance
object JSON Object Depends on op The JSON-encoded data associated with the operation, if any
parameters JSON Object No The parameters associated with the request (e.g. count=true)
requestId String Yes A unique identifier for each request issued by the client. If specified, this id is returned as a property in the response and can be used to match asynchronous responses with the corresponding request.

Examples Using WebSockets

The following examples refer to a user-defined TempByZip type, which is assumed to have three properties:

When referencing specific resources, the resource’s _id property, which is automatically assigned by Vantiq when a resource is created must be used. In the examples, 5696c2511de9a702175aadbb is used as an example _id.

Objective: Retrieve a list of all user-created and system-defined database types.

{
    "op": "select",
    "resourceName": "types"
}

Objective: Insert a new weather reading object of the TempByZip type.

{
    "op": "insert",
    "resourceName": "TempByZip",
    "object": { "temperature": 32, "zipCode": 96160, "timeZone": "Pacific" },
    "parameters": { "requestId": "94563Reading" }
}

Objective: Update an existing weather reading object of the TempByZip type.

{
    "op": "update",
    "resourceName": "TempByZip",
    "resourceId": "5696c2511de9a702175aadbb",
    "object": { "temperature": 90, "zipCode": 96160, "timeZone": "Pacific" }
}

Objective: Insert or update a weather reading object of the TempByZip type, depending on whether the ZIP Code already exists.

{
    "op": "upsert",
    "resourceName": "TempByZip",
    "object": { "temperature": 32, "zipCode": 95389, "timeZone": "Pacific" }
}

Objective: Delete all the TempByZip objects associated with particular time zone.

{
    "op": "delete",
    "resourceName": "TempByZip",
    "parameters": { "where": { "timeZone": "Pacific" } }
}

Objective: Replace the temperature value with 100 in a specific TempByZip object.

{
    "op": "patch",
    "resourceName": "TempByZip",
    "resourceId": "5696c2511de9a702175aadbb",
    "object": [ { "op": "replace", "path": "temperature", "value": 100 } ]
}

Objective: Retrieve all TempByZip objects with temperatures below 32:

{
    "op": "aggregate",
    "resourceName": "TempByZip",
    "parameters": [{"$match":{"temperature":{"$lt":32}}}]
}