API Reference Guide

Overview

The Vantiq API provides access to the Vantiq resource model 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 supported API bindings which allow the API to be used from different contexts. These bindings are:

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

Accessing the API

The Vantiq Platform 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 developer cloud or production systems. 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. See the User and Namespace Administration Guide for more details.

Authentication

Vantiq resources are secure and the requesting client must authenticate before issuing requests against the services. The details of this process are specific to each binding and are covered in those sections.

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 count of selected instances will be returned (how is binding specific) 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 count of inserted instances will be returned (how is binding specific) 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 count of deleted instances will be returned (how is binding specific) 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. 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 has an indication of success or failure, the result of the operation, and possibly meta-data which helps further describe the result. Each of the bindings communicates these differently as will be described in the next section.

API Bindings

REST Over HTTP Binding

Authentication

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.

Resource URIs

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.

Operation to HTTP Method Mapping

API operations are issued to the HTTP REST API by mapping them to the HTTP method. The following table describes all the supported operations and their corresponding HTTP structure. All URIs are relative to /api/v#/resources:

Operation URL Path Query Params Method Description
SELECT /[custom/]<name> where, props, sort, count, page, limit GET Returns all matching resource instances of type <name>.
SELECT /[custom/]<name>/<id> GET Returns a single instance of the resource of type <name> identified by <id>.
INSERT /[custom/]<name> count POST Inserts a new instance of resources of type <name>
UPDATE /[custom/]<name>/<id> PUT Updates an existing instance of resources of type <name> identified by <id>
UPSERT /[custom/]<name>?upsert=true POST Upserts a new instance of resources of type <name>
DELETE /[custom/]<name> count DELETE Removes all matching resources of type <name>.
DELETE /[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 /<name>/<id> POST Publishes the JSON payload in the request body. Only topics and sources support the publish operation.
EXECUTE /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 /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.
AUTHORIZED USERS /namespaces/<namespace>/authorizedUsers GET Returns the users who are authorized in the specified namespace (must be admin)
NAMESPACE AUTHORIZATION /namespaces/<namespace> POST Depending on the command specified, will either authorize a user for the given namespace or revoke authorization from an existing user. The arguments to the command are supplied as a JSON document. See the Namespaces resource for more details.

Response Status

Operation responses are communicated as the result of the operation’s HTTP request. The overall status of the request is communicated via the HTTP response code. 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:

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.

As mentioned, the VAIL binding communicates these as exceptions which can be inspected and processed programmatically.

Response Meta-data

The response meta-data provides additional information relating to the requested operation. For example, if the operation requested a count, that information is returned as meta-data. When using the API with REST over HTTP, the meta-data is communicated via HTTP response headers. Currently the following headers are supported:

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 Binding

WebSockets URI

Vantiq supports 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)

Authentication

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": "system.credentials",
    "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": "system.credentials",
    "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.

Request Format

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)

In addition to the standard operation parameters, the WebSockets binding also supports the requestId parameter. If used it should be set to a unique, opaque string (such as a UUID). The server will ensure that the same value will be returned in the response associated with this specific request (allows matching of responses to requests when processing multiple, simultaneous requests).

Response Format

The response from the server is communicated as a JSON object with the following properties:

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
  }
}

Response Meta-Data

Any response meta-data (such as counts) will be communicates as the first element of the response body and not in the headers.

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",
    "object": [{"$match":{"temperature":{"$lt":32}}}]
}

VAIL Binding

The VAIL binding provides API access via the ResourceAPI built-in service.

Request Format

In the VAIL binding API requests are issued using the Similar to WebSockets API requests are represented as JSON objects with 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)

Response Format

The execution of an operation results in a sequence which contains the operation’s results. Depending on the output of the operation this sequence may contain zero, one, or many elements and the element types may be any of those supported by VAIL.

Response Errors

Response errors are communicated via VAIL exceptions. These exceptions can be caught and examined just like any other VAIL exception (see TRY-CATCH-FINALY for more details).

Examples Using VAIL

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

Objective: Compute the average of all TempByZip objects grouped by zip:

var avgTmpMsg = {
    "op": "aggregate",
    "resourceName": "TempByZip",
    "object": [{"$group":{"_id": "$zipCode", "avgTmp": {"$avg": "$temperature"}, "count": { "$sum": 1 }}}]
}

var avgByZip = ResourceAPI.executeOp(avgTmpMsg)
... process resulting sequence ...

Objective: Find the users who are authorized in the current namespace:

var authZUsers = {}
authZUsers.op = "getAuthorizedUsers"
authZUsers.resourceName = "system.namespaces"
authZUsers.resourceId = namespace()

ResourceAPI.executeOp(authZUsers)