Developer Hub

Welcome to the EVRYTHNG Developer Hub! Here you will find all the information you need to create your EVRYTHNG apps and integrations. We have conceptual guides, walkthroughs, and tutorials as well as a complete API reference.

Featured Pages

Suggest Edits

Standard API Introduction

 

The Standard API is a REST API between client apps and the EVRYTHNG Platform. It is used to create and manage projects, applications, products, thngs, actions, and more platform resources.

This API Reference section of the Developer Hub contains sections for each module of the API. The overview of each section goes through conceptual material about how the module works. Example requests are shown for all endpoints for at least the main Create, Read, Update, and Destroy (CRUD) request types for each resource. Most example requests shown here are written first in HTTP specification format, then as examples for cURL, evrythng.js, and evrythng-java-sdk if appropriate.

For more conceptual detail on the more high-level aspects of the EVRYTHNG API as well as walkthroughs and SDKs, check out the Documentation section.


Requests

The API root domain is shown below, and must be used for all API requests. URLs shown with no domain use the API root as their domain unless otherwise specified:

  • API - https://api.evrythng.com
  • Dashboard - https://dashboard.evrythng.com

For applications that require it, a separate European region is also available:

  • API - https://api-eu.evrythng.com
  • Dashboard - https://dashboard-eu.evrythng.com

Note

Once you create your account, remember which region you used to help avoid problems with authentication in the future.


Important Notes

  • All timestamps are Unix time in milliseconds (i.e, number of milliseconds since Unix epoch Jan 1 1970). Time zones are currently not supported, therefore client applications must handle the conversion from UNIX timestamps to appropriate time zone themselves.

  • Strings are always in UTF-8 format.

  • For all resources that include customFields, identifiers, or properties you may not use ., NULL, or $ in any key name.

 

Multiple Operators can be associated with an EVRYTHNG Platform account. Through use of the Roles API each can be given the appropriate permissions and levels of scope necessary for their role in the application.

From each Operator's perspective, they each have a unique access to each account they are associated with, and are granted an Operator API Key for each.


API Status
Stable:
/accounts
/accounts/:accountId
/accounts/:accountId/shortDomains
Beta:
/accounts/:accountId/domains


AccountDocument Data Model

.name (string)
    Friendly name of this resource. Must be between 1 and 30
    characters.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields
    associated with the resource.

.imageUrl (string)
    The account Dashboard logo.

.tfaRequired (boolean, read-only)
    Whether two-factor authentication is required for this
    account.
{
  "type": "object",
  "description": "An object representing a Platform account.",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name of this resource. Must be between 1 and 30 characters.",
      "minLength": 1,
      "maxLength": 30
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "imageUrl": {
      "type": "string",
      "description": "The account Dashboard logo."
    },
    "tfaRequired": {
      "type": "boolean",
      "description": "Whether two-factor authentication is required for this account.",
      "readOnly": true
    }
  },
  "x-filterable-fields": [ "name" ]
}
{
  "id": "UhpHrg39QCy9dsSddN8xhwnb",
  "createdAt": 1471862431010,
  "customFields": {
    "region": "en-gb"
  },
  "updatedAt": 1510593794364,
  "name": "Example Account",
  "imageUrl": "https://avatars1.githubusercontent.com/u/5732010?v=4&s=460",
  "tfaRequired": true
}

AccessDocument Data Model

The AccessDocument contains role and authentication information for an account.

.account (string, read-only)
    The account ID.

.apiKey (string, read-only)
    The account's Operator API key.

.id (string, read-only)
    The ID of this resource.

.operator (string, read-only)
    The account's user ID.

.role (string)
    The ID of the currently assigned role.
{
  "type": "object",
  "description": "An object representing an account's access record.",
  "properties": {
    "account": {
      "type": "string",
      "description": "The account ID.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "apiKey": {
      "type": "string",
      "description": "The account's Operator API key.",
      "readOnly": true,
      "pattern": "^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]{80}$"
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "operator": {
      "type": "string",
      "description": "The account's user ID.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "role": {
      "type": "string",
      "description": "The ID of the currently assigned role.",
      "minLength": 4,
      "maxLength": 24
    }
  }
}
{
  "id": "57bad69fc18104025b292da8",
  "account": "UhpHrg39QCy9dsSddN8xhwnb",
  "operator": "UEp4rDGsnpCAF6xABbys5Amc",
  "apiKey": "AGiWrH5OteA4aHiMFiwnwF08p3PQvPIr9GJX...",
  "role": "admin"
}

Read All Accounts

Read an array of all accounts visible to an Operator with their API key.

GET /accounts
Authorization: $OPERATOR_API_KEY
evrythng accounts list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/accounts'
const operatorApiKey = '$OPERATOR_API_KEY';

EVT.api({
  url: '/accounts',
  authorization: operatorApiKey
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UhpHrg39QCy38dht93kiuwnb",
    "createdAt": 1471862430889,
    "customFields": {},
    "updatedAt": 1471862431010,
    "name": "Main Account",
    "tfaRequired": false
  }
]

Read an Account

Read an account by its ID by sending a GET request to the /accounts/:accountId endpoint.

GET /accounts/:accountId
Content-Type: application/json
Authorization: $OPERATOR_API_KEY
evrythng accounts $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/accounts/UhpHrg39QCy9dsSddN8xhwnb'
const accountId = 'UhpHrg39QCy9dsSddN8xhwnb';
const operatorApiKey = '$OPERATOR_API_KEY';

EVT.api({
  url: `/accounts/${accountId}`,
  authorization: operatorApiKey
}).then(console.log);
HTTP/1.1 200 Ok
Content-Type: application/json

{
  "id": "UhpHrg39QCy9dsSddN8xhwnb",
  "createdAt": 1471862430889,
  "customFields": {},
  "updatedAt": 1471862431010,
  "name": "Main Account",
  "tfaRequired": false
}

Update an Account

Update an account with new user information or custom fields by sending an AccountDocument with only the fields to be updated. For example, the name, or imageUrl which will be displayed in the Dashboard.

PUT /accounts/:accountId
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

AccountDocument (subset)
evrythng accounts $id update $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/accounts/UhpHrg39QCy38dht93kiuwnb'
  -d '{ 
    "imageUrl": "https://example.com/image.png" 
  }'
const accountId = 'UhpHrg39QCy38dht93kiuwnb';
const operatorApiKey = '$OPERATOR_API_KEY';

const update = { 
  imageUrl: 'https://example.com/image.png'
};

EVT.api({
  url: `/accounts/${accountId}`,
  method: 'PUT',
  authorization: operatorApiKey,
  data: update
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UhpHrg39QCy38dht93kiuwnb",
  "createdAt": 1471862430889,
  "customFields": {},
  "updatedAt": 1471862431010,
  "name": "Updated Account Name",
  "imageUrl": "https://example.com/image.png",
  "tfaRequired": false
}

Read all Short Domains

Read all short domains available to an account.

GET /accounts/:accountId/shortDomains
Authorization: $OPERATOR_API_KEY
evrythng accounts $id short-domains list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/accounts/UhpHrg39QCy9dsSddN8xhwnb/shortDomains'
const operatorApiKey = '$OPERATOR_API_KEY';
const accountId = 'UGYYcfmsCy9nQtRwwYcgnfKb';

EVT.api({
  url: `/accounts/${accountId}/shortDomains`,  
  authorization: operatorApiKey
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

[
  "tn.gg"
]

DomainDocument Data Model

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.id (string, read-only)
    The ID of this resource.

.accountId (string)
    The account this domain belongs to.

.domain (string)
    The domain URL.
{
  "type": "object",
  "description": "A single account domain entry.",
  "properties": {
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "accountId": {
      "type": "string",
      "description": "The account this domain belongs to.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "domain": {
      "type": "string",
      "description": "The domain URL."
    }
  }
}
{
  "createdAt": 1519385011833,
  "updatedAt": 1519385011833,
  "id": "5a8ff9b3a1b3f60013492de7",
  "accountId": "UnFQtmpUMtQBY8wRaEystb5h",
  "domain": "ratqa.tn.gg"
}

Read all Domains

GET /accounts/:accountId/domains
Authorization: $OPERATOR_API_KEY
evrythng accounts $id domains list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/accounts/UnFQtmpUMtQBY8wRaEystb5h/domains'
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "createdAt": 1519385011833,
    "updatedAt": 1519385011833,
    "id": "5a8ff9b3a1b3f60013492de7",
    "accountId": "UnFQtmpUMtQBY8wRaEystb5h",
    "domain": "ratqa.tn.gg"
  }
]
 

A fundamental concept in the EVRYTHNG Platform are actions. An action simply represents a discrete event or real-world actions performed by an app, user, or device within an application, and usually created on a product or a Thng to establish an association corresponding to the real world event. For example, an action created on a Thng could represent a 'switched on' event when the Thng's device was switched on.

Actions are usually created by an Application User within an application and a Thng, product, or collection ID must be specified as the target. In addition to specifying a resource in an action, it is also possible to create an action through the resource itself using aliased actions.


Action Types

The basic actions types supported within the Platform are scans, implicitScans, checkins and shares. It is also possible to create your own action types. Custom action types must always start with an underscore (_).

See the Action Types section for more information on using custom action types.


Action Context

When reading actions, the ?context=true query parameter can be used to include the context field in the response. This includes useful contextual information about the creation of the action. See the ActionContextDocument Data Model section for more information.


API Status
Stable:
/actions/:type
/actions/:type/:actionId
/products/:productId/actions/:actionType
/thngs/:thngId/actions/:actionType
/collections/:collectionId/actions/:actionType

ActionDocument Data Model

.type (string)
    The action type.

.id (string, read-only)
    The ID of this resource.

.user (string, read-only)
    The EVRYTHNG ID of the user who has performed this action.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.createdByProject (string, read-only)
    The EVRYTHNG ID of the project who has performed this
    action.

.thng (string)
    The EVRYTHNG ID of the Thng this action was carried out on.

.product (string)
    The EVRYTHNG product ID associated with the Thng this action
    was carried out on.

.collection (string)
    The EVRYTHNG ID of the collection this action was carried
    out on. Custom action types only.

.timestamp (integer, read-only)
    The timestamp when the action took place. Filled
    automatically if unspecified.

.identifiers (object)
    Various identifiers (EPC, ISBN, etc.) as a JSON object with
    one or more key-value pairs.

.location (LocationDocument)

.locationSource (string, one of 'sensor', 'geoIp', 'unknown', 'place')
    The method used to find the location where the action took
    place, and requires `location` to also be set. If a GPS was
    used (with user permission granted), `sensor` is specified.
    Otherwise an estimate is made based on the apparent
    location, which may not be the device itself.

.context (ActionContextDocument)

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields
    associated with the resource.

.scopes (ScopesDocument)

.tags (array of string)
    Array of string tags associated with this resource.

.reactions (array of ReactionDocument, read-only)
    An array of Redirector reactions that occured from this
    action.
{
  "type": "object",
  "description": "An object representing a Platform action.",
  "properties": {
    "type": {
      "type": "string",
      "description": "The action type."
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "user": {
      "type": "string",
      "description": "The EVRYTHNG ID of the user who has performed this action.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "createdByProject": {
      "type": "string",
      "description": "The EVRYTHNG ID of the project who has performed this action.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "thng": {
      "type": "string",
      "description": "The EVRYTHNG ID of the Thng this action was carried out on.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "product": {
      "type": "string",
      "description": "The EVRYTHNG product ID associated with the Thng this action was carried out on.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "collection": {
      "type": "string",
      "description": "The EVRYTHNG ID of the collection this action was carried out on. Custom action types only.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "timestamp": {
      "type": "integer",
      "description": "The timestamp when the action took place. Filled automatically if unspecified.",
      "readOnly": true,
      "minimum": 0
    },
    "identifiers": {
      "type": "object",
      "description": "Various identifiers (EPC, ISBN, etc.) as a JSON object with one or more key-value pairs."
    },
    "location": { "$ref": "LocationDocument" },
    "locationSource": {
      "type": "string",
      "description": "The method used to find the location where the action took place, and requires `location` to also be set. If a GPS was used (with user permission granted), `sensor` is specified. Otherwise an estimate is made based on the apparent location, which may not be the device itself.",
      "enum": [ "sensor", "geoIp", "unknown", "place" ]
    },
    "context": { "$ref": "ActionContextDocument" },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "scopes": { "$ref": "ScopesDocument" },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "reactions": {
      "type": "array",
      "description": "An array of Redirector reactions that occured from this action.",
      "items": { "$ref": "ReactionDocument" },
      "readOnly": true
    }
  },
  "x-filterable-fields": [ "timestamp", "identifiers.<key>", "tags", "type", "user", "context.city", "context.countryCode", "thng", "product", "collection" ]
}
{
  "id": "U4aPKKSEWy9nQQRaaghRasaa",
  "createdAt": 1510914839892,
  "customFields": {
    "region_code": "en_gb"
  },
  "tags": [
    "example",
    "actions"
  ],
  "timestamp": 1510914839892,
  "type": "scans",
  "user": "UnRPKGnUMQtVEPaaageq5ehk",
  "location": {
    "latitude": 51.4333,
    "longitude": 0.1833,
    "position": {
      "type": "Point",
      "coordinates": [
        0.1833,
        51.4333
      ]
    }
  },
  "locationSource": "geoIp",
  "context": {
    "city": "Crayford",
    "region": "England",
    "countryCode": "GB",
    "userAgentName": "Unknown",
    "operatingSystemName": "Unknown",
    "timeZone": "Europe/London"
  },
  "reactions": [
    {
      "type": "redirection",
      "redirectUrl": "https://google.com",
      "redirectionContext": {
        "constants": {
          "constant_key": "constant_value"
        }
      }
    }
  ],
  "createdByProject": "UmxHK6K8BXsa9KawRh4bTbqc",
  "createdByApp": "U3pxRQh2eD8RtKwaRgerfQgc",
  "identifiers": {
    "ean_13": "786432786349"
  },
  "thng": "U4wpchcBqm8hhqwwag8kgnqc"
}

See also: LocationDocument, ScopesDocument, ReactionDocument, ActionContextDocument


ActionContextDocument Data Model

.ipAddress (string, read-only)
    The geolocation IP address of the action.

.city (string, read-only)
    The geolocation city of the action, based on the IP address.

.region (string, read-only)
    The wider region of the action.

.countryCode (string, read-only)
    The country of the action.

.userAgentName (string, read-only)
    The user agent name of the action creator's browser or other
    client.

.userAgent (string, read-only)
    The user agent of the action creator's browser or other
    client.

.operatingSystemName (string, read-only)
    Name of the action creator's client operating system.

.timeZone (string, read-only)
    The timezone string, such as Europe/Paris
{
  "type": "object",
  "description": "Object containing contextual data about the action creator.",
  "properties": {
    "ipAddress": {
      "type": "string",
      "description": "The geolocation IP address of the action.",
      "readOnly": true
    },
    "city": {
      "type": "string",
      "description": "The geolocation city of the action, based on the IP address.",
      "readOnly": true
    },
    "region": {
      "type": "string",
      "description": "The wider region of the action.",
      "readOnly": true
    },
    "countryCode": {
      "type": "string",
      "description": "The country of the action.",
      "readOnly": true
    },
    "userAgentName": {
      "type": "string",
      "description": "The user agent name of the action creator's browser or other client.",
      "readOnly": true
    },
    "userAgent": {
      "type": "string",
      "description": "The user agent of the action creator's browser or other client.",
      "readOnly": true
    },
    "operatingSystemName": {
      "type": "string",
      "description": "Name of the action creator's client operating system.",
      "readOnly": true
    },
    "timeZone": {
      "type": "string",
      "description": "The timezone string, such as Europe/Paris",
      "readOnly": true
    }
  }
}

ReactionDocument Data Model

.type (string, read-only, one of 'redirection')
    The reaction type.

.redirectUrl (string, read-only)
    The redirection URL.

.redirectionContext (object, read-only)
    Object of redirection context values.
{
  "type": "object",
  "description": "A single reaction from Redirector.",
  "properties": {
    "type": {
      "type": "string",
      "description": "The reaction type.",
      "enum": [ "redirection" ],
      "readOnly": true
    },
    "redirectUrl": {
      "type": "string",
      "description": "The redirection URL.",
      "readOnly": true
    },
    "redirectionContext": {
      "type": "object",
      "description": "Object of redirection context values.",
      "readOnly": true
    }
  }
}

Create an Action

Create a new action of the specified type.

Notes

  • all can be used as type. In this case, the action type must be supplied in the payload.

  • When using /actions/all with a custom action type, the payload can contain only the type, and does not require a target thng, product, or collection.

POST /actions/:type
Content-Type: application/json
Authorization: $APP_USER_API_KEY

ActionDocument
evrythng actions $type create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $APP_USER_API_KEY" \
  -X POST "https://api.evrythng.com/actions/scans" \
  -d '{
    "product": "UmAkSdqe69QVhswwRYNdbxna",
    "type": "scans",
    "identifiers": {
      "sapId": "KDL-46EX402AEP",
      "event_Id": "027242784925"
    },
    "customFields": {
      "color": "blue"
    }
  }'
const actionType = 'scans';
const productId = 'UmAkSdqe69QVhswwRYNdbxna';
    
const action = {
  type: actionType,
  product: productId,
  identifiers: {
    sapId: "KDL-46EX402AEP",
    event_Id: "027242784925"
  },
};

app.action(actionType).create(action).then(console.log);

// with the nested resources
app.product(productId).action(actionType).create().then(console.log);

// or on the entity itself
app.product(productId).read().then((product) => {
  product.action(actionType).create().then(console.log);
});
String productId = "UmAkSdqe69QVhswwRYNdbxna";

ScanAction action = new ScanAction();
action.setProduct(productId);  // Could also be a product or shortId
apiManager.actionService().actionCreator(action).execute();
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/actions/scans/UGByEXMEq9QBE8aRaYNeYnkb

{
  "id": "UGByEXMEq9QBE8aRaYNeYnkb",
  "createdAt": 1497528007035,
  "timestamp": 1497528007035,
  "type": "scans",
  "user": "UmAFxMDnqQ9VEsRwaErAxfrr",
  "location": {
    "latitude": 48.86,
    "longitude": 2.34,
    "position": {
      "type": "Point",
      "coordinates": [
        2.34,
        48.86
      ]
    }
  },
  "locationSource": "unknown",
  "createdByProject": "UGdkbcyhqQtVEsaaRhrASatf",
  "createdByApp": "UmAFxcdSMt9VE8awRE7dba9n",
  "product": "UmAkSdqe69QVhswwRYNdbxna"
}

Read an Action

Application Users and Operators can read an action by its ID. Both the Application User and Operator API keys can be used. You can use all as the action type to access the actions of unknown type.

GET /actions/:actionType/:actionId
Authorization: $OPERATOR_API_KEY
evrythng actions $type $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/actions/scans/Uh7HKqtFryhmBaShGHVySmeg'
const productId = 'UhrHD9BnngymSrapaakKrq9g';
const actionId = 'Uh7HKqtFryhmBaShGHVySmeg';
const actionType = 'scans';

// Read a user's specific 'scan' action
user.action(actionType, actionId).read().then(console.log);

// Read user product's specific scan action
user.product(productId).action(actionType, actionId).read().then(console.log);

// Read a user's specific actions (regardless of type)
user.action('all').read().then(console.log);
String actionId = "Uh7HKqtFryhmBaShGHVySmeg";

// The class parameter should match the class of the action being read
// For example, ScanAction.class for the 'scan' action type
ScanAction action = apiManager.actionService().actionReader(ScanAction.class, actionId).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "Uh7HKqtFryhmBaShGHVySmeg",
  "createdAt": 1473953016966,
  "timestamp": 1473953016966,
  "type": "scans",
  "location": {
    "latitude": 51.5142,
    "longitude": -0.0931,
    "position": {
      "type": "Point",
      "coordinates": [
        -0.0931,
        51.5142
      ]
    }
  },
  "locationSource": "geoIp",
  "thng": "Uh74neTHnDcmbNwpaRmUhEht",
  "product": "UhrHD9BnngymSrapaakKrq9g"
}

Read all Actions of a Type

Read all actions of a given type. For example: GET /actions/scans for all the scans actions. The result may be paginated if there are more than 30 items.

A special type all can be used to get all actions regardless of their type.

See Action Types to see how to read and manage action types.

GET /actions/:type
Authorization: $OPERATOR_API_KEY
evrythng actions $type list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/actions/scans'
const actionType = 'scans';
const productId = 'UGTdRHP4BDsa95waRhqfYhTh';

// Read user's product's most recent scans:
user.action(actionType).read({
  params: {
    filter: {
      product: productId
    }
  }
}).then(console.log);

// Above, simplified
user.product(productId).action(actionType).read().then(console.log);

// Read user's most recent scans:
user.action(actionType).read().then(console.log);

// Read all recent actions in this app:
user.action('all').read().then(console.log);
Iterator<PVector<Action>> actions = apiManager.actionService().iterator().perPage(10).filter("type=scans").execute();
while(actions.hasNext()) {
    PVector<Action> page = actions.next();
    for(Action action : page) {
        System.out.println("action: " + action.toString());
    }
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UmBSBbDBBg8atKaRwXFBDwct",
    "createdAt": 1497448804712,
    "timestamp": 1497448804712,
    "type": "scans",
    "user": "UGBxVbDeVXsRt5aRwhQTngep",
    "location": {
      "latitude": 39.02,
      "longitude": 125.75,
      "position": {
        "type": "Point",
        "coordinates": [
          125.75,
          39.02
        ]
      }
    },
    "locationSource": "unknown",
    "createdByProject": "UmSqCDt5BD8atKRRagdqUnAa",
    "createdByApp": "UGxqWERBBgsatKwRwgG9Kfcb",
    "product": "UGTdRHP4BDsa95waRhqfYhTh"
  }
]

Read an Action with Context

The ?context=true query parameter can be used to include the context field in the action read.

GET /actions/:actionType/:actionId?context=true
Authorization: $OPERATOR_API_KEY
evrythng actions $type $id read --context
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/actions/scans/UkqgkMW5egsatKawRYbywqeb?context=true'
const actionType = 'scans';
const actionId = 'UkqgkMW5egsatKawRYbywqeb';

user.action(actionType, actionId).read({
  params: {
    context: true
  }
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UkqgkMW5egsatKawRYbywqeb",
  "createdAt": 1489407066926,
  "customFields": {
    "ExternalScan": true
  },
  "timestamp": 1489407066926,
  "type": "scans",
  "user": "Ukqg2MbseDPwtKwwaYE6QfRs",
  "location": {
    "latitude": 57.75,
    "longitude": -0.9133,
    "position": {
      "type": "Point",
      "coordinates": [
        -0.9133,
        57.75
      ]
    }
  },
  "locationSource": "geoIp",
  "context": {
    "city": "Dartford",
    "region": "England",
    "countryCode": "GB",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
    "timeZone": "Europe/London"
  },
  "createdByProject": "UF5hQHxMBg8a9pwwRYxqXkqp",
  "createdByApp": "UkMgYtdEVDsaQKaRwgdAWsdn",
  "thng": "Uk6XkAPbBXPwtKwawDAepMmm",
  "product": "UFKE9nHBBg8atKaawgVrKKbs"
}

Delete an Action

Delete a single action by ID.

DELETE /actions/:type/:actionId
Authorization: $OPERATOR_API_KEY
evrythng actions $type $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/actions/scans/UE9Akx9WaMQwgWdpMYAGUr9p'
const actionType = 'scans';
const actionId = 'UE9Akx9WaMQwgWdpMYAGUr9p';

operator.action(actionType, actionId).delete();
String actionId = "UE9Akx9WaMQwgWdpMYAGUr9p";

// The class should match the type of action to be deleted
// For example, ScanAction.class for the 'scan' action type
apiManager.actionService().actionDeleter(ScanAction.class, actionId).execute();
HTTP/1.1 200 OK

Create Multiple Actions

It is possible to create multiple actions at the same time using the /actions/all endpoint. Each action in the payload array must state the action type. Different types can be used at the same time for different actions.

POST /actions/all
Authorization: $OPERATOR_API_KEY
Content-Type: application/json

[ ActionDocument, ... ]
curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/actions/all' \
  -d '[
    {
      "type": "scans",
      "thng": "Um2MEbqHMm8Eh6aaaDBSQkHm"
    },
    {
      "type": "checkins",
      "thng": "Um2MEbqHMm8Eh6aaaDBSQkHm"
    }
  ]'
const actions = {
  type: 'scans',
  thng: 'UmCygXyDeXsw9KwwRhnnGg2a'
}, {
  type: 'checkins',
  thng: 'UmCygXyDeXsw9KwwRhnnGg2a'
};

operator.action('all').create(actions).then(console.log);
HTTP/1.1 201 Created
Content-Type: application/json

[
  {
    "id": "UmpbCgWRMGsEEqRRwgYEbtEs",
    "createdAt": 1504794192742,
    "timestamp": 1504794192742,
    "type": "scans",
    "location": {
      "latitude": 51.45,
      "longitude": 0.2167,
      "position": {
        "type": "Point",
        "coordinates": [
          0.2167,
          51.45
        ]
      }
    },
    "locationSource": "geoIp",
    "context": {
      "city": "Dartford",
      "region": "England",
      "countryCode": "GB",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
      "timeZone": "Europe/London"
    },
    "thng": "Um2MEbqHMm8Eh6aaaDBSQkHm",
    "product": "U3EtU2k3BD8wQpwwR6EMXgKb"
  },
  {
    "id": "U3KbCgfRMmPhh6wwagYYbtka",
    "createdAt": 1504794192756,
    "timestamp": 1504794192756,
    "type": "checkins",
    "location": {
      "latitude": 51.45,
      "longitude": 0.2167,
      "position": {
        "type": "Point",
        "coordinates": [
          0.2167,
          51.45
        ]
      }
    },
    "locationSource": "geoIp",
    "context": {
      "city": "Dartford",
      "region": "England",
      "countryCode": "GB",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
      "timeZone": "Europe/London"
    },
    "thng": "Um2MEbqHMm8Eh6aaaDBSQkHm",
    "product": "U3EtU2k3BD8wQpwwR6EMXgKb"
  }
]

Aliased Actions

It is also possible to use alias endpoints to create or read actions performed on a specific Thng, product or collection using its ID. The available endpoints are:

  • /products/:productId/actions/:actionType - Actions on a specific product
  • /thngs/:thngId/actions/:actionType - Actions on a specific Thng
  • /collections/:collectionId/actions/:actionType - Actions on a specific collection

Use the same payload as for /actions/:actionType endpoint. The action's product, thng, or collection property must match the ID that is specified in the URL, or in this special case may be omitted from the payload. The responses are of the same format as the Read all actions of a type operation.

Note

Only custom action types can be used for aliased actions.

Create an Aliased Action

The examples below show aliased action creation on a product, but are also applicable for Thngs and collections in the same /:type/:id/actions/:actionType pattern.

POST /products/:productId/actions/:actionType
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ActionDocument
evrythng products $id actions create $payload
curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/products/Uk7KFKGKBXPwQKawwDYF9bPr/actions/_Active' \
  -d '{
  "type": "_Active",
  "product": "Uk7KFKGKBXPwQKawwDYF9bPr"
}'
const productId = 'Uk7KFKGKBXPwQKawwDYF9bPr';
const actionType = '_Active';

const payload = {
  product: productId,
  type: actionType
};

operator.product(productId).action(actionType).create(payload)
	.then(console.log);

Read all Aliased Actions on a Resource

GET /products/:productId/actions/:actionType
Authorization: $OPERATOR_API_KEY
evrythng products $id actions list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/products/Uk7KFKGKBXPwQKawwDYF9bPr/actions/_Active'
const productId = 'Uk7KFKGKBXPwQKawwDYF9bPr';
const actionType = '_Active';

operator.product(productId).action(actionType).read()
	.then(console.log);

Read an Aliased Action

GET /products/:productId/actions/:actionType/:actionId
Authorization: $OPERATOR_API_KEY
evrythng products $id actions $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/products/Uk7KFKGKBXPwQKawwDYF9bPr/actions/_Active/UHr9xPR8qG8YhMaawEPcbh4p'
const productId = 'Uk7KFKGKBXPwQKawwDYF9bPr';
const actionType = '_Active';
const actionId = 'UHr9xPR8qG8YhMaawEPcbh4p';

operator.product(productId).action(actionType, actionId).read()
	.then(console.log);
Suggest Edits

Action Types

 

An Operator can define new custom action types for the account. When defining these action types, it's possible to add specific custom fields and tags to aid in sorting. An action type can be regarded as a class identifier of an individual action, much in the same way that a product should be used to model classes of Thngs.

Action types that are created in a project scope can later be shared with other projects using the 'Add to another project' button in the Dashboard, or through the REST API. See Scoping for more information on sharing resources between projects.

Note

Custom action types must always start with an underscore (_).


API Status
Stable:
/actions
/actions/:type


ActionTypeDocument Data Model

.name (string, read-only)
    The name of the action type. Custom action types must begin
    with an underscore.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.description (string)
    Friendly description of this resource.

.tags (array of string)
    Array of string tags associated with this resource.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields
    associated with the resource.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object describing a custom action type.",
  "properties": {
    "name": {
      "type": "string",
      "description": "The name of the action type. Custom action types must begin with an underscore.",
      "readOnly": true
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "description": {
      "type": "string",
      "description": "Friendly description of this resource."
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "name" ]
}
{
  "id": "UHwsppkh69tVhPRaaDEpdCbg",
  "createdAt": 1510914951694,
  "customFields": {
    "region_code": "en_sc"
  },
  "tags": [
    "example",
    "actionType"
  ],
  "updatedAt": 1510914951694,
  "name": "_AlertFired",
  "description": "An alert was fired."
}

See also: ScopesDocument


Action Type Customization

When an action type is viewed in the Dashboard, it is displayed with some additional visual elements if the type's customFields includes any of the following optional items:

  • color - The hexadecimal color value, including #, used in the action table margin.
  • displayname - The friendly name of the action type, which does not require an underscore, unlike name.
  • icon - A Glyphicon code for an icon representing the meaning of this action type.

Create an Action Type

Submit a valid ActionTypeDocument to the /actions endpoint to create a custom action type.

POST /actions
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ActionTypeDocument
evrythng action-types create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/actions' \
  -d '{
    "name": "_Arrived"
  }'
const actionType = {
  name: '_Arrived'
};

operator.actionType().create(actionType).then(console.log);
ActionType actionType = new ActionType();
actionType.setName("_Arrived");	// Must start with '_'
apiManager.actionService().actionTypeCreator(actionType).execute();
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/actions/Uh8cBH7dMnXd8NbmyxB7tdqk

{
  "id": "Uh8cBH7dMnXd8NbmyxB7tdqk",
  "createdAt": 1474448083763,
  "updatedAt": 1474448083763,
  "name": "_Arrived"
}

Read all Action Types

Action types can be retrieved by a GET on the /actions endpoint. The action types are returned with the built-in types coming first, followed by the custom types sorted by descending creation date. The result may be paginated if there are more than 30 items.

GET /actions
Authorization: $APPLICATION_USER_API_KEY
evrythng action-types list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/actions'
user.actionType().read().then(console.log);
List<ActionType> types = apiManager.actionService().actionTypesReader().execute();
for(ActionType type : types) {
    System.out.println(type.getName());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "name": "checkins"
  },
  {
    "name": "implicitScans"
  },
  {
    "name": "scans"
  },
  {
    "name": "shares"
  },
  {
    "id": "UGFqk8eCVXPRQKwwwgGcHmGh",
    "createdAt": 1502383685794,
    "tags": [
      "custom"
    ],
    "updatedAt": 1505491159408,
    "name": "_Arrived"
  }
]

Update an Action Type

Update an action type by making a PUT request.

PUT /actions/:name
Content-Type: application/json
Authorization: $APPLICATION_USER_API_KEY

ActionTypeDocument (subset)
evrythng action-types $type update $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/actions/_Arrived' \
  -d '{
    "tags": [ "example" ]
  }'
const type = '_Arrived';
const update = {
  tags: [ "example" ]
};

user.actionType(type).update(update).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "Uk7WdgFAMQtehsRawgdwEkCn",
  "createdAt": 1490368131932,
  "tags": [
    "example"
  ],
  "updatedAt": 1497450736023,
  "name": "_Arrived"
}

Delete an Action Type

You can delete an action type in a similar manner to creating one using the actionType.

Note

The default action types cannot be deleted.

Note

Deleting an action type will result in the deletion of all actions created of that type as well.

DELETE /actions/:actionType
Authorization: $OPERATOR_API_KEY
evrythng action-types $type delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/actions/_Arrived'
const actionType = '_Arrived';

operator.actionType(actionType).delete().then(console.log);
String actionType = "_Arrived";

apiManager.actionService().actionTypeDeleter(actionType).execute();
HTTP/1.1 200 OK
Suggest Edits

Applications

 

The EVRYTHNG Platform allows developers to create applications inside their projects. An application resource will usually correspond to an actual web or native applications (remote HTTP clients) that can interact with the EVRYTHNG API.

In this way all resources that are associated with the real-world counterpart app can be correctly scoped and grouped accordingly, for the purpose of an application as well as its Application Users. Multiple applications can exist inside a project resource, with each granted its own Application and Trusted Application API Keys that can be used to manipulate only those resources in the application's project scope.


API Status
Stable:
/applications/me
/projects/:projectId/applications
/projects/:projectId/applications/:applicationId
/projects/:projectId/applications/:applicationId/secretKey


ApplicationDocument Data Model

.name (string)
    Friendly name of this resource.

.socialNetworks (object)
    An array of social networks that this application will 
    support.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.tags (array of string)
    Array of string tags associated with this resource.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.

.description (string)
    Friendly description of this resource.

.project (string, read-only)
    ID of the platform project this application belongs to.

.defaultUrl (string)
    The URL where the default client app for this application is 
    deployed.

.appApiKey (string, read-only)
    The API key available to the application.

.defaultRole (string)
    The default Application User role new Application Users 
    created in this application will be given.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object describing a platform application.",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name of this resource."
    },
    "socialNetworks": {
      "type": "object",
      "description": "An array of social networks that this application will support.",
      "default": {}
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "description": {
      "type": "string",
      "description": "Friendly description of this resource."
    },
    "project": {
      "type": "string",
      "description": "ID of the platform project this application belongs to.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "defaultUrl": {
      "type": "string",
      "description": "The URL where the default client app for this application is deployed."
    },
    "appApiKey": {
      "type": "string",
      "description": "The API key available to the application.",
      "readOnly": true,
      "pattern": "^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]{80}$"
    },
    "defaultRole": {
      "type": "string",
      "description": "The default Application User role new Application Users created in this application will be given.",
      "minLength": 13,
      "maxLength": 24
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "name", "project" ]
}
{
  "id": "U4axGkeeeq8r97aaRgBB9fTr",
  "createdAt": 1510053956736,
  "customFields": {
    "key": "value"
  },
  "tags": [
    "example",
    "app"
  ],
  "updatedAt": 1510915098055,
  "name": "Test Application",
  "description": "Example description",
  "project": "UmxHK6K8BXsa9KawRh4bTbqc",
  "socialNetworks": {},
  "defaultUrl": "https://google.com",
  "defaultRole": "base_app_user",
  "appApiKey": "a4AjjHgehcKlGajImlgmrtInvSnYLG80yZ7sDEl..."
}

See also: ScopesDocument


Create an Application

Creates an application within the project specified with projectId.

The object returned contains the appApiKey parameter, which is an Application API key that must be used within an external application to issue calls to the API. However, because this API key can be hard coded within external applications (e.g. mobile/JS) and is visible to anyone, it can be used only for a very limited set of operations (create users, read a product, send actions etc.).

POST /projects/:projectId/applications
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ApplicationDocument
evrythng projects $id applications create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/projects/URG5FDahhBePgNfHVkHTkama/applications' \
  -d '{ 
    "name": "Mobile App", 
    "socialNetworks": {} 
  }'
const projectId = 'URG5FDahhBePgNfHVkHTkama';

const application = {
  name: 'Mobile App',
  socialNetworks: {}
};

operator.project(projectId).application().create(application).then(console.log);
String projectId = "URG5FDahhBePgNfHVkHTkama";
HashMap<String, SocialNetwork> networks = new HashMap<String, SocialNetwork>();

Application application = new Application();
application.setName("Mobile App");
application.setSocialNetworks(networks);
apiManager.applicationService().applicationCreator(projectId, application).execute();
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/projects/URG5FDahhBePgNfHVkHTkama/applications/UmAFxcdSMt9VE8awRE7dba9n

{
  "id": "UmAFxcdSMt9VE8awRE7dba9n",
  "name": "Mobile App",
  "project": "URG5FDahhBePgNfHVkHTkama",
  "appApiKey": "cYFWnAiRTaNeOnj8ejc0qQg9FgwyPDV4UXDPQ...",
  "createdAt": 1372243297475,
  "updatedAt": 1372243297475,
  "socialNetworks": {},
  "defaultRole": "app_user_admin"
}

Read Applications in a Project

Read a list of applications within the project specified with projectId. The result may be paginated if there are more than 30 items.

GET /projects/:projectId/applications
Authorization: $OPERATOR_API_KEY
evrythng projects $id applications list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/projects/U2meqbNWegsaQKRRaDUmpssr/applications'
const projectId = 'U2meqbNWegsaQKRRaDUmpssr';

operator.project(projectId).application().read().then(console.log);
String projectId = "U2meqbNWegsaQKRRaDUmpssr";

List<Application> apps = apiManager.applicationService().applicationsReader().project(projectId).list().getResult();
for(Application app : apps) {
    System.out.println(app.toString());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "Umbn56MmBDsatpaawg6XgKfk",
    "name": "Mobile App",
    "project": "U2meqbNWegsaQKRRaDUmpssr",
    "appApiKey": "cYFWnAiRTaNeOnj8ejc04qQg9Fgwy3PDV4UXDP...",
    "createdAt": 1372243297475,
    "updatedAt": 1372243297475,
    "socialNetworks": {},
    "defaultRole": "app_user_admin"
  }
]

Read an Application

Returns a single application matching the applicationId within the project specified by projectId.

GET /projects/:projectId/applications/:applicationId
Authorization: $OPERATOR_API_KEY
evrythng projects $id applications $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/projects/URG5FDahhBePgNfHVkHTkama/applications/UF3Vqb7D6G8EhMwaRYgQ2pFc'
const projectId = 'URG5FDahhBePgNfHVkHTkama';
const applicationId = 'UF3Vqb7D6G8EhMwaRYgQ2pFc';

operator.project(projectId).application(applicationId).read().then(console.log);
String projectId = "URG5FDahhBePgNfHVkHTkama";
String applicationId = "UF3Vqb7D6G8EhMwaRYgQ2pFc";

Application app = apiManager.applicationService().applicationReader(projectId, applicationId).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UF3Vqb7D6G8EhMwaRYgQ2pFc",
  "name": "Mobile App",
  "project": "URG5FDahhBePgNfHVkHTkama",
  "appApiKey": "cYFWnAiRTaNeOnj8ejc0qQg9FgwyPDV4UXDPQsBjCg6...",
  "createdAt": 1372243297475,
  "updatedAt": 1372243297475,
  "socialNetworks": {},
  "defaultRole": "base_app_user"
}

Update an Application

Update a single application by ID.

PUT /projects/:projectId/applications/:applicationId
Authorization: $OPERATOR_API_KEY
Content-Type: application/json

ApplicationDocument (subset)
evrythng projects $id applications $id update $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/projects/URG5FDahhBePgNfHVkHTkama/applications/UF3Vqb7D6G8EhMwaRYgQ2pFc' \
  -d '{ 
    "name": "Updated App Name" 
  }'
const projectId = 'URG5FDahhBePgNfHVkHTkama';
const applicationId = 'UF3Vqb7D6G8EhMwaRYgQ2pFc';

const update = {
  name: 'Updated App Name'
};

operator.project(projectId).application(applicationId).update(update)
  .then(console.log);
String projectId = "URG5FDahhBePgNfHVkHTkama";
String applicationId = "UF3Vqb7D6G8EhMwaRYgQ2pFc";

// Read an application
Application application = apiManager.applicationService().applicationReader(applicationId).project(projectId).execute();

// Update it
application.setDescription("Updated application description");
apiManager.applicationService().applicationUpdater(projectId, applicationId, application).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UF3Vqb7D6G8EhMwaRYgQ2pFc",
  "name": "Updated App Name",
  "project": "URG5FDahhBePgNfHVkHTkama",
  "appApiKey": "cYFWnAiRTaNeOnj8ejc0qQg9FgwyPDV4UXDPQ...",
  "createdAt": 1372243297475,
  "updatedAt": 1372243297475,
  "socialNetworks": {},
  "defaultRole": "app_user_admin"
}

Delete an Application

Delete an application by ID. This action cannot be undone.

DELETE /projects/:projectId/applications/:applicationId
Authorization: $OPERATOR_API_KEY
evrythng projects $id applications $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/projectId/UmACfDggBDswQpawRk4pAqDq/applications/U3dCCgDYBDswtpawRYBMcnHb'
const projectId = 'UmACfDggBDswQpawRk4pAqDq';
const applicationId = 'U3dCCgDYBDswtpawRYBMcnHb';

operator.project(projectId).application(applicationId).delete();
String projectId = "UmACfDggBDswQpawRk4pAqDq";
String applicationId = "U3dCCgDYBDswtpawRYBMcnHb";

apiManager.applicationService().applicationDeleter(applicationId).project(projectId).execute();
HTTP/1.1 200 OK

Read the Trusted Application API Key

Read the Trusted Application API Key for the application with applicationId. This is a secret key that has access to more endpoints than the standard Application API key.

Note

Operator users with read-only permissions (i.e.: global_read and project_read) will not be able to see this endpoint, or read the Trusted Application API Key.

GET /projects/:projectId/applications/:applicationId/secretKey
Authorization: $OPERATOR_API_KEY
evrythng projects $id applications $id secret-key read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/projects/URG5FDahhBePgNfHVkHTkama/applications/UF3Vqb7D6G8EhMwaRYgQ2pFc/secretKey'
const operatorApiKey = '$OPERATOR_API_KEY';
const projectId = 'UG4WExTKBqPr9NwRa3twYDnk';
const applicationId = 'UG4NWfQ7BMPN97wawGQRrxtm';

EVT.api({
  url: `/projects/${projectId}/applications/${applicationId}/secretKey`,
  authorization: operatorApiKey
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

{
  "secretApiKey": "cYFWnAiRTaNeOnj8ejc0qQg94FgwyPDV1PQsBjCg..."
}

Read Self Application

An application can read its own metadata without knowledge of which project it is in using the /applications/me endpoint with its Application API key.

GET /applications/me
Authorization: $APPLICATION_API_KEY
curl -H "Authorization: $APPLICATION_API_KEY" \
  -X GET 'https://api.evrythng.com/applications/me'
const trustedAppApiKey = '$TRUSTED_APPLICATION_API_KEY';

EVT.api({
  url: '/applications/me',
  authorization: trustedAppApiKey
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UmSMbD9ACTtn99aaa2gfnKgp",
  "createdAt": 1495013107545,
  "customFields": {},
  "updatedAt": 1495013620339,
  "name": "Mobile App",
  "project": "UGSMSDs5fc9n9QaRwkXC4pDg",
  "socialNetworks": {},
  "appApiKey": "gxQiaD7gwHiuyCIexB4NMSpxu56565BxZemIqud..."
}

Update Self Application

The /applications/me endpoint can also be used to allow an application to update its own meta data using its Trusted Application API Key.

PUT /applications/me
Content-Type: application/json
Authorization: $TRUSTED_APPLICATION_API_KEY

ApplicationDocument (subset)
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $TRUSTED_APPLICATION_API_KEY" \
  -X PUT 'https://api.evrythng.com/applications/me' \
  -d '{ 
		"customFields": {
      "somekey": "somevalue"
    }
  }'
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UGf5HamGBDPa95waah7Can5c",
  "createdAt": 1499177113975,
  "customFields": {
    "somekey": "somevalue"
  },
  "updatedAt": 1510565887701,
  "name": "Test Application",
  "project": "UmxHK6K8BXsa9KawRh4bTbqc",
  "socialNetworks": {},
  "defaultRole": "base_app_user",
  "appApiKey": "gXHaJVTBUrgYS3gDqVoy06WqXNM4zeGU..."
}
Suggest Edits

Application Users

 

Each EVRYTHNG application can create individual Application Users that are scoped to just that application. Each of these have their own personal details and login credentials, and are designed to serve as an access to only those resources that the user is concerned with. Each Application User is granted an Application User API Key when they are created, as well as on each subsequent log in. This key is revoked if and when an Application User logs out or is deleted.

For example, a commercial traceability application might create an Application User for each of the staff members that interact with the traceability solution, and can then use their own API key to create actions or access other resources to carry out their job.

In addition to named Application Users, an application may also create anonymous counterparts, which are not intended to be remembered or uniquely identified, but exist purely to allow a user-level access to resources or to perform a once-only action, and do not need to persist for any given length of time. For example, a single scan of an on-pack QR code would use an anonymous user to allow a more detailed action record to be created.


API Status
Stable:
/auth/evrythng
/auth/evrythng/facebook
/auth/evrythng/users
/users
/users/:evrythngUser


ApplicationUserDocument Data Model

.id (string, read-only)
    The ID of this resource.

.email (string)
    E-mail address of the user. Unique within the app.

.firstName (string)
    User's first name.

.lastName (string)
    User's last name.

.password (string)
    The user's password.

.birthday (BirthdayDocument)

.gender (string, one of 'male', 'female')
    User's gender.

.timezone (string)
    The current timezone for the user. For example: 
    `Pacific/Honolulu` or `Europe/Uzhgorod`).

.locale (string)
    The default language tag for the user, complied with RFC 
    5646.

.photo (string)
    URL of the user's photo.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.

.tags (array of string)
    Array of string tags associated with this resource.

.project (string, read-only)
    The project ID of the application this user belongs to.

.app (string, read-only)
    The ID of the application this user belongs to.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.access (ApplicationUserAccessDocument)

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object describing an Application User.",
  "properties": {
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "email": {
      "type": "string",
      "description": "E-mail address of the user. Unique within the app."
    },
    "firstName": {
      "type": "string",
      "description": "User's first name."
    },
    "lastName": {
      "type": "string",
      "description": "User's last name."
    },
    "password": {
      "type": "string",
      "description": "The user's password.",
      "minLength": 8,
      "maxLength": 30
    },
    "birthday": { "$ref": "BirthdayDocument" },
    "gender": {
      "type": "string",
      "description": "User's gender.",
      "enum": [ "male", "female" ]
    },
    "timezone": {
      "type": "string",
      "description": "The current timezone for the user. For example: `Pacific/Honolulu` or `Europe/Uzhgorod`)."
    },
    "locale": {
      "type": "string",
      "description": "The default language tag for the user, complied with RFC 5646."
    },
    "photo": {
      "type": "string",
      "description": "URL of the user's photo."
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "project": {
      "type": "string",
      "description": "The project ID of the application this user belongs to.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "app": {
      "type": "string",
      "description": "The ID of the application this user belongs to.",
      "readOnly": true,
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "access": { "$ref": "ApplicationUserAccessDocument" },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "email", "firstName", "lastName" ]
}
{
  "id": "UnaP5scsfcQ4tQwaRXEyheBd",
  "createdAt": 1510915630522,
  "customFields": {
    "age": 25
  },
  "tags": [
    "example",
    "user"
  ],
  "updatedAt": 1510915657700,
  "email": "example@evrythng.com",
  "firstName": "Example",
  "lastName": "User",
  "timezone": "Pacific/Honolulu",
  "locale": "en-gb",
  "photo": "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg",
  "birthday": {
    "day": 1,
    "month": 12,
    "year": 1992
  },
  "gender": "male",
  "project": "UmxHK6K8BXsa9KawRh4bTbqc",
  "app": "U3pxRQh2eD8RtKwaRgerfQgc"
}

See also: BirthdayDocument, ScopesDocument, ApplicationUserAccessDocument


BirthdayDocument Data Model

.day (integer)

.month (integer)

.year (integer)
{
  "type": "object",
  "description": "An Application User's birthday.",
  "properties": {
    "day": {
      "type": "integer",
      "minimum": 1,
      "maximum": 31
    },
    "month": {
      "type": "integer",
      "minimum": 1,
      "maximum": 12
    },
    "year": {
      "type": "integer",
      "minimum": 1900
    }
  }
}

ApplicationUserAccessDocument Data Model

.id (string, read-only)
    The access ID.

.project (string, read-only)
    The ID of the project the user belongs to.

.app (string, read-only)
    The ID of the application the user belongs to.

.user (string, read-only)
    This user's ID.

.actor (string, read-only)
    The accessing actor's ID.

.role (string, read-only)
    The ID of the user's role.

.apiKey (string, read-only)
    The actor's Application User API Key.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.
{
  "type": "object",
  "description": "Object containing data relevant to an Application User's platform access.",
  "properties": {
    "id": {
      "type": "string",
      "description": "The access ID.",
      "readOnly": true
    },
    "project": {
      "type": "string",
      "description": "The ID of the project the user belongs to.",
      "readOnly": true
    },
    "app": {
      "type": "string",
      "description": "The ID of the application the user belongs to.",
      "readOnly": true
    },
    "user": {
      "type": "string",
      "description": "This user's ID.",
      "readOnly": true
    },
    "actor": {
      "type": "string",
      "description": "The accessing actor's ID.",
      "readOnly": true
    },
    "role": {
      "type": "string",
      "description": "The ID of the user's role.",
      "readOnly": true
    },
    "apiKey": {
      "type": "string",
      "description": "The actor's Application User API Key.",
      "readOnly": true
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    }
  }
}

Create an Application User

Note

This endpoint creates an unactivated user. Use the /auth/evrythng/users/:evrythngUser/validate endpoint to finish the creation process once the user has confirmed their email address etc.

See the Activate an Application User page for more information.

Create a new unactivated Application User, using the Application API Key. The email must be a unique identifier within the app, therefore your application will not be able to create more than one user with the same email address.

If the user doesn't exist yet, the platform will create a new user and return an activationCode in the response. Before the user gets activated and can access data in the API, the application will need to send back the activation code to our API for that user as shown below. This additional step allows the client application to ensure that the email provided has been validated to be real and accessible by the user.

POST /auth/evrythng/users
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

ApplicationUserDocument
evrythng app-users create $payload
curl -i -H "Content-type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/auth/evrythng/users' \
  -d '{ 
    "firstName": "Example First Name", 
    "lastName": "Example Last Name", 
    "email": "example@test.com", 
    "password": "password" 
  }'
const appUser = {
  email: 'ivan@evrythng.com',
  password: 'mypa5w0rd',
  firstName: 'Ivan',
  lastName: 'Cherepanov',
  customFields: {
    catchphrase: 'crzht No blockers crzht'
  }
};

app.appUser().create(appUser).then(console.log);
ApiManager appApiManager = new ApiManager(APPLICATION_API_KEY);

User user = new User();
user.setEmail("example@test.com");
user.setPassword("password");
user.setFirstName("Example First Name");
user.setLastName("Example Last Name");

Credentials creds = apiManager.authService().evrythngUserCreator(user).execute();
System.out.println("evrythngUser=" + creds.getEvrythngUser());
System.out.println("activationCode=" + creds.getActivationCode());
HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "evrythngUser": "UmVxeKVQeg8wQ5waaXsrda2t",
  "activationCode": "3RwaN5LQ",
  "status": "inactive",
  "email": "example@test.com"
}

Activate an Application User

Once a user has been created with the /auth/evrythng/users endpoint, it needs to be activated (by the client application) by sending a POST request including the activationCode.

If the activationCode is correct, the user will be activated and authenticated, and the Application User will be assigned an Application User API Key.

If you forget the activationCode between creating the Application User and activation, you can retrieve it using a GET request to the /users/:evrythngUser/status endpoint.

POST /auth/evrythng/users/:evrythngUser/validate
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

{
  "activationCode": String
}
evrythng app-users $id validate $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/auth/evrythng/users/:evrythngUser/validate' \
  -d '{ 
    "activationCode": "348s83j" 
  }'
const appUser = {
  email: 'some.one@anyone.com',
  password: 'password', 
  firstName: 'Some',
  lastName: 'One'
};

// Create and validate in one step!
app.appUser().create(appUser).then((newUser) => {
  return newUser.validate();
}).then(() => console.log('Validated!'));

// OR
// Validate a previously created user
otherUser.validate().then((validated) => {
  console.log(`Validated app user: ${validated}`);

  // User can now login successfully using app.login(...) or,
  // be used immediately by creating a User scope:
  const userScope = new EVT.User({
    id: validated.evrythngUser, 
    apiKey: validated.evrythngApiKey
  }, app);
});
// Credentials from a previous invokation of evrythngUserCreator()
creds = apiManager.authService().evrythngUserValidator(creds.getEvrythngUser(), creds.getActivationCode()).execute();
System.out.println("status=" + creds.getStatus());
HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "status": "active",
  "evrythngUser": "UmVxeKVQeg8wQ5waaXsrda2t",
  "evrythngApiKey": "AGCSBhdt07tnLxtObxqObpOI91234S4KBfot9T5oi..."
}

Read all Application Users

Read all available Application Users using the Trusted Application API Key or the Operator API Key. The result may be paginated if there are more than 30 items.

GET /users
Authorization: $OPERATOR_API_KEY
evrythng app-users list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/users'
operator.user().read().then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UmVxeKVQeg8wQ5waaXsrda2t",
    "createdAt": 1497451343302,
    "updatedAt": 1497451406584,
    "email": "some@email.com",
    "firstName": "Test",
    "lastName": "User",
    "project": "UmxHK6K8BXsa9KawRh4bTbqc",
    "app": "Umbn56MmBDsatpaawg6XgKfk"
  }
]

Read an Application User

GET /users/:userId
Authorization: $OPERATOR_API_KEY
evrythng app-users $id read
curl -i -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/users/UGN5FtfdV6PNQ7aRaXwCrhHp'
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UGN5FtfdV6PNQ7aRaXwCrhHp",
  "createdAt": 1507561299992,
  "updatedAt": 1507561300298,
  "email": "appuser-1507561299766@example.com",
  "firstName": "Bora",
  "lastName": "Horza",
  "project": "UmrK2QWAegPwQ5waRh4QMQfp",
  "app": "UGr5kQCUBMsr9NwwR2wPeKbe"
}

Update an Application User

Authorised Application Users can modify their own data (including the password) using their Application User API key. An Operator is also allowed to update data of users registered within their accounts.

PUT /users/:evrythngUser
Authorization: $OPERATOR_API_KEY
Content-Type: application/json

ApplicationUserDocument (subset)
evrythng app-users $id update $payload
curl -i -H "Content-type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/users/UYtUFbWKRq9wDCd5qEdmccyp' \
  -d '{ 
    "firstName": "New First Name" 
  }'
var update = {
  firstName: 'New First Name'
};

// User scope can update itself
user.update(update).then(console.log);

// Operator can also update a user on its behalf
operator.user(userId).update(update).then(console.log);
var email = "test@example.com";
var password = "s3cr3T@";

// Read data by authenticating
Credentials creds = new Credentials(email, password);
creds = appApiManager.authService().evrythngUserAuthenticator(creds).execute();
System.out.println("User ID: " + creds.getEvrythngUser());
System.out.println("User API key: " + creds.getEvrythngApiKey());
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UYtUFbWKRq9wDCd5qEdmccyp",
  "createdAt": 1494924625617,
  "updatedAt": 1497451913694,
  "email": "test@example.com",
  "firstName": "New First Name",
  "lastName": "user",
  "project": "UmxHK6K8BXsa9KawRh4bTbqc",
  "app": "Umbn56MmBDsatpaawg6XgKfk"
}

Update an Application User's Password

An Application User can update the password they use to log into an application using a PUT request. However, they must also provide their current password as a form of verification.

PUT /users/:evrythngUser
Content-Type: application/json
Authorization: $APPLICATION_USER_API_KEY

{
  "password": "M7@29P6Stk9zF5gX5@4!c3Vm",
  "oldPassword": "0ldp455w0rd"
}
evrythng app-users $id update $payload
curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X PUT 'https://api.evrythng.com/users/UmQ6dEBKMG8YEMaRah3FVf3f' \
  -d '{
    "password": "M7@29P6Stk9zF5gX5@4!c3Vm",
    "oldPassword": "0ldp455w0rd"
  }'
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UmQ6dEBKMG8YEMaRah3FVf3f",
  "createdAt": 1509701451010,
  "updatedAt": 1509701489615,
  "email": "example-user@example.net",
  "firstName": "Example",
  "lastName": "User",
  "project": "UmQMUhSFqm8hYMaawhmkBChr",
  "app": "U3QMUhTn6GPEhMwawE32Bfkr"
}

Delete an Application User

Delete an Application User by ID. This action cannot be undone.

DELETE /users/:evrythngUser
Authorization: $OPERATOR_API_KEY
evrythng app-users $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/users/UYtUFbWKRq9wDCd5qEdmccyp'
const userId = 'UYtUFbWKRq9wDCd5qEdmccyp';

operator.user(userId).delete().then(console.log);
HTTP/1.1 200 OK

Create an Anonymous User

Create an anonymous user that does not need to be activated by including the ?anonymous=true parameter in the query parameters and body of the request.

This kind of user is useful for tracking devices not pre-associated with a user.

POST /auth/evrythng/users?anonymous=true
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

{
  "anonymous": true
}
evrythng app-users anonymous create
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/auth/evrythng/users?anonymous=true' \
  -d '{ 
    "anonymous": true 
  }'
// Create the user and store the returned credentials
app.appUser().create({
  anonymous: true
}).then((anonymousUser) => {
  // Returns a ready to use User Scope that doesn't need validation
  console.log(`Created anonymous user: ${anonymousUser}`);
  
  // Store anonymous user details locally
  if(window.localStorage) {
    localStorage.userId = anonymousUser.id;
    localStorage.apiKey = anonymousUser.apiKey;
  }
});

// Load the user from localstorage
const anonymousUser = new EVT.User({
  id: localStorage.userId,
  apiKey: localStorage.apiKey
}, app);
User user = new User();
Credentials creds = apiManager.authService().evrythngUserCreator(user).queryParam("anonymous", "true").execute();
System.out.println("Anonymous ID: " + creds.getEvrythngUser());
System.out.println("Anonymous API key: " + creds.getEvrythngApiKey());
HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "evrythngUser": "U3BSenB6Bg8w9pRawk5ycwdt",
  "status": "anonymous",
  "email": "anon-12d855f0-510f-11e7-bc07-0bd000cf37af.app-umbn56mmbdsatpaawg55gkfk@anon.evrythng.com",
  "evrythngApiKey": "Tw9Tw6M4s0ip5k12Pi2xd4VpcliT0H41tW912343X07Z...",
  "socialNetwork": "evrythng"
}

Log a User In

Authenticate (log in) an existing user with their email and password used at registration time. Apps can authenticate existing users using the pair email + password and receiving an Application User API key. The request is made with an ApplicationUserLoginDocument.

If the user is active and if the credentials are correct, the platform will then return a new Application User API key which can be used until the user is logged out.

POST /auth/evrythng
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

ApplicationUserLoginDocument
evrythng app-users login $payload
curl -i -H "Content-type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/auth/evrythng' \
  -d '{ 
    "email": "someone@somewhere.com", 
    "password": "s0mepassw0rd" 
  }'
const credentials = {
  email: 'someone@somewhere.com',
  password: 's0mepassw0rd'
};

// Login user (with EVRYTHNG Auth) and create user scope
// app.login('evrythng', {...}); behaves the same way
app.login(credentials).then((response) => {
  // evrythng.js automatically creates a User scope.
  const userScope = response.user;
  
  // Now every call using user will use their userApiKey
  userScope.thng().read().then(console.log);
});
Credentials creds = new Credentials(email, password);
creds = appApiManager.authService().evrythngUserAuthenticator(creds).execute();
System.out.println("User ID: " + creds.getEvrythngUser());
System.out.println("User API key: " + creds.getEvrythngApiKey());
HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "socialNetwork": "evrythng",
  "evrythngUser": "U3BSenB6Bg8w9pRawk5ycwdt",
  "evrythngApiKey": "cYFWnAiRTaNeOnj8ejc0qQg9Fg4wyPDV4U31sB2j...",
  "email": "someone@somewhere.com"
}

Log a User In with Access Info

Similar to the standard login process, an Application API Key can log a user in and receive access information about that user at the same time. If the actor and user have the same value, the user is authenticating themselves. If these values differ, the actor is logging in on behalf of the user.

In this case, the email property in the request payload can be replaced with the evrythngUser ID, if known.

POST /users/login
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

ApplicationUserLoginDocument
curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/users/login' \
  -d '{
    "email": "someone@somewhere.com",
    "password": "s0omepassw0rd"
  }'
const credentials = {
  email: 'someone@somewhere.com',
  password: 's0mepassw0rd'
};

app.login(credentials).then(console.log);
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "UmW8bewpVD8RQKRaR2qpDtyh",
  "createdAt": 1499337739424,
  "updatedAt": 1499337754551,
  "email": "someone@somewhere.com",
  "firstName": "Some",
  "lastName": "One",
  "project": "UGBNTUbf6tQVhswwagmfVrcm",
  "app": "U3fdqbMpqt9VhsaRwED3xmtn",
  "access": {
    "id": "595e141ab4a46a2c00b7bdf1",
    "project": "UGBNTUbf6tQVhswwagmfVrcm",
    "app": "U3fdqbMpqt9VhsaRwED3xmtn",
    "user": "UmW8bewpVD8RQKRaR2qpDtyh",
    "actor": "UmW8bewpVD8RQKRaR2qpDtyh",
    "role": "base_app_user",
    "apiKey": "Lz5RtLxwDP3kS6VawbKip2DrQJkKAiTu01lGMjfS..."
  }
}

ApplicationUserLoginDocument Data Model

.email (string)
    The email address assigned to the Application User.

.password (string)
    The Application User's password used at account creation 
    time.
{
  "type": "object",
  "description": "An object representing an Application User login request.",
  "properties": {
    "email": {
      "type": "string",
      "description": "The email address assigned to the Application User."
    },
    "password": {
      "type": "string",
      "description": "The Application User's password used at account creation time."
    }
  }
}

Create/Authenticate a User via External Profiles

EVRYTHNG applications can also sign up and login users using their accounts on external services.

In practice, apps must log in users via Facebook and then create a user account on EVRYTHNG that is bound to his Facebook account. This is done by posting the user's Facebook access token on the /auth/facebook endpoint.

Note that the authentication uses the Application API Key (returned in the appApiKey parameter of the object of your application, as seen in Applications. When creating a new user, the platform will send the Access token to Facebook to validate the user has been created by the correct Facebook application (the access token corresponds to the appId of the Facebook object in the corresponding application).

Important

The EVRYTHNG Platform uses the provided Facebook token to retrieve information about the user. But some of this user data is only visible if the corresponding permissions have been requested upon authenticating the user through the Facebook API.

In order to allow the user to be created properly you must ask for at least the email and user_birthday permissions.

POST /auth/facebook
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

{
  "access": {
    "expires": Timestamp,
    "token": String        // Facebook Token
  }
}
HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "socialNetwork": "facebook",
  "access": {
    "expires": Timestamp,
    "token": String          // Facebook-Token
  },
  "socialNetworkId": String, // Facebook User Id,
  "appId": String,           // Facebook App Id,
  "evrythngUser": Ref,
  "evrythngApiKey": UserApiKey
}

Authenticate a User via Facebook with Evrythng.js

Note

evrythng.js asynchronously loads the Facebook Javascript SDK for you. You do not need to authenticate with Facebook another way.

The following login calls open a generic Facebook login popup. Once authenticated with Facebook you're also authenticated with EVRYTHNG.

  1. Using Facebook default permissions (email):
// Ensure socialNetworks.facebook is set with ID and token first
const app = new EVT.app({
  apiKey: APPLICATION_API_KEY,
  facebook: true,
});

app.login('facebook').then((response) => {
  const fbStatus = response.status;
  const user = response.user;

  // Now every call using user will use their Application User API Key
});
  1. Using custom permissions (be sure to have them enabled in your Facebook Application):
app.login('facebook', { 
  scope: 'email,user_birthday' 
}).then((response) => {
  const fbStatus = response.status;
  const user = response.user;

  // Now every call using user will use their UserApiKey
});

Read more about Facebook login permissions and connection status in the Facebook API reference.

Return Parameters

  • socialNetwork - String
    Indicates the external social network type. At the moment, only "facebook" is supported.

  • access - Object
    The access token for this user on the social network, and includes the user token and the expiration time. Example:

    {
      "token": "XXX",
      "expires": Timestamp
    }
    
  • socialNetworkId - String
    The user ID of the user on that social network (e.g. the Facebook user ID.).

  • appId - String
    The application ID on the social network the user has signed in (e.g. the Facebook app ID).

  • evrythngUser - String
    The EVRYTHNG user ID corresponding for the that user.

  • evrythngApiKey - String
    This is the unique EVRYTHNG USER API Key that uniquely identifies this user within this application. This API Key must be used for all subsequent activities by the user within the application for all calls to the EVRYTHNG platform (read Thngs, post actions, etc.).


Log the User Out

User access token can be invalidated by using it to call to /auth/all/logout regardless of the method the user authenticated with (EVRYTHNG or 3rd party). The user's API key will become invalid after the call.

POST /auth/all/logout
Content-Type: application/json
Authorization: $APPLICATION_USER_API_KEY
evrythng app-user logout
curl -i -H "Content-type: application/json" \
  -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X POST 'https://api.evrythng.com/auth/all/logout'
user.logout();
// creds obtained from a previous invokation of evrythngUserAuthenticator()
apiManager.authService().authLogouter().apiKey(creds.getEvrythngApiKey()).execute();

The platform acknowledges the logout operation in the response body.

HTTP/1.1 201 CREATED
Content-Type: application/json

{
  "logout": "ok"
}

Share Access with Other Users

An Application User can share limited access to their scoped resources with another existing Application User. This works by assigning an existing Application User role to the email address belonging to the second Application User.

Once the second user has been given an access, they will be able to use a new API key available to them to view and modify resources belonging to the granting user's account, according to the shared role's permissions.

Notes

  • The role being assigned must be in scope of the authenticating Application User's role, and also must be in the same project scope.

  • If the role being assigned to a secondary user is the same as the authenticating Application User's role, then it must be in scope of itself.


Jump To ↓

Create an Access
Read all Available Accesses
Delete an Access


Create an Access

Create a new Application User access for another Application User by specifying their email address and role to be assigned.

In the response, user is the ID of the Application User granting the new access, and actor is the ID of the receiving Application User.

POST /accesses
Content-Type: application/json
Authorization: $APPLICATION_USER_API_KEY

{
  "email": "test@example.com",
  "role": "59a676cc6404572c00294433"
}
evrythng accesses create $payload
curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X POST 'https://api.evrythng.com/accesses' \
  -d '{
    "email": "test@example.com",
    "role": "59a676cc6404572c00294433"
  }'
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "59ad60d9b24413002c7d7695",
  "project": "UG4WExTKBqPr9NwRa3twYDnk",
  "app": "UG4NWfQ7BMPN97wawGQRrxtm",
  "user": "UGHrfg5XB6PNQraaamtRNbts",
  "actor": "UGH7CG5WeqP7tNRawGQwrydc",
  "role": "59a676cc6404572c00294433",
  "customFields": {
    "email": "test@example.com"
  }
}

Read all Available Accesses

An Application User can read all the available accesses (including API keys) they have been given. By default they will have at least one - their own application access. Any additional accesses created for them using the process described above will also appear here.

For any access, actor is the ID of the assigned Application User, and user is the ID of the Application User that granted the access.

GET /accesses
Authorization: $APPLICATION_USER_API_KEY
evrythng accesses list
curl -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X GET 'https://api.evrythng.com/accesses'
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "5a05acfa9bc1420031fa786d",
    "project": "UnRCn5syM3shYqaawYDn4bbs",
    "app": "UnaCn5P3MmshEMRwaED4nbyd",
    "user": "UHaf46PWMGPYE6wRwhDHnbVd",
    "actor": "UHaf46PWMGPYE6wRwhDHnbVd",
    "apiKey": "QW3W8iIjBZfdIIdI7Ik3FHxKPJbLMj3jfwTCxoUmp..."
  },
  {
    "id": "5a05ad909bc1420031fa7874",
    "project": "UnRCn5syM3shYqaawYDn4bbs",
    "app": "UnaCn5P3MmshEMRwaED4nbyd",
    "user": "U4wCHMDDMGPYEMawREg4Hxdb",
    "actor": "UHaf46PWMGPYE6wRwhDHnbVd",
    "role": "5a05ac349bc1420031fa7860",
    "customFields": {
      "email": "seconduser@evrythng.com"
    },
    "apiKey": "L4PDu9RUMvFttmsiYV8ASUG5nxInAQPItHICNSkCq..."
  }
]

Delete an Access

Either the granting or receiving Application User can revoke the access with a DELETE request. After this is done, the granting user must create a new access before the receiving user can access the granting user's resources again.

DELETE /accesses/:accessId
Authorization: $APPLICATION_USER_API_KEY
evrythng accesses $id delete
curl -H "Authorization: $APPLICATION_USER_API_KEY" \
  -X DELETE 'https://api.evrythng.com/accesses/59afba76dff5ea002c88c4e9'
HTTP/1.1 204 No Content
Suggest Edits

Collections

 

A collection resource allows you to group a set of Thngs. This can make it easier for Application Users to manage all the Thngs they created while using an application. This works by assigning a reference to the collection to each Thng, and listing the Thngs that reside in each collection.

Collections have a similar data model to other resources in the Platform (a name and description, tags, and properties etc.) and are created in a similar manner. Once a collection has been created, users can add or remove manually Thngs to that collection, using the /thngs sub-resource of each collection. See below for example operations.

In addition to specifying a collection in an action, it is also possible to create an action through the collection itself using aliased actions.


API Status
Stable:
/collections
/collections/:collectionId
/collections/:collectionId/thngs
/collections/:collectionId/collections
/collections/:collectionId/collections/:childCollectionId


CollectionDocument Data Model

.name (string)
    Friendly name of this resource.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.description (string)
    Friendly description of this resource.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.

.tags (array of string)
    Array of string tags associated with this resource.

.identifiers (object)
    Various identifiers (EPC, ISBN, etc.) as a JSON object with 
    one or more key-value pairs.

.collections (array of string, read-only)
    An array of collection IDs of any collections this 
    collection belongs to.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object representing a Platform collection, which can contain groups of Thngs.",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name of this resource."
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "description": {
      "type": "string",
      "description": "Friendly description of this resource."
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "identifiers": {
      "type": "object",
      "description": "Various identifiers (EPC, ISBN, etc.) as a JSON object with one or more key-value pairs."
    },
    "collections": {
      "description": "An array of collection IDs of any collections this collection belongs to.",
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
      },
      "readOnly": true
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "collections", "identifiers", "name", "tags" ]
}
{
  "id": "UHa8qAMtVgPRQKaawEf5hfQm",
  "createdAt": 1510917071603,
  "customFields": {
    "host": "8974237894"
  },
  "tags": [
    "example",
    "collection"
  ],
  "updatedAt": 1510917071603,
  "name": "Example Collection",
  "description": "An example collection resource.",
  "identifiers": {
    "ean_8": "32833232"
  }
}

See also: ScopesDocument
__

Create a Collection

Create a new collection.

POST /collections
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

CollectionDocument
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/collections' \
  -d '{
    "name": "Office-322",
    "description": "The collection of all thngs in office 322",
    "customFields": {
      "insured": "true"
    },
    "tags": [ "Office", "Zurich", "322", "EVRYTHNG" ],
    "identifiers": {
      "collectionCode": "OZ322",
      "collectionReferenceNumber": "12345"
    }
  }'
const collection = {
  name: 'Office-322',
  description: 'The collection of all thngs in office 322',
  customFields: {
    insured: 'true'
  },
  tags: [ 'Office', 'Zurich', '322', 'EVRYTHNG' ],
  identifiers: {
    collectionCode: 'OZ322',
    collectionReferenceNumber: '12345'
  }
};

user.collection().create(collection).then(console.log);
Collection collection = new Collection();
collection.setName("Office-322");
apiManager.collectionService().collectionCreator(collection).execute();
HTTP/1.1 201 Created
Location: https://api.evrythng.com/collections/UmSyPf5RBg8RtpRaag9F9s3b
Content-Type: application/json

{
  "id": "UmSyPf5RBg8RtpRaag9F9s3b",
  "createdAt": 1346865441719,
  "updatedAt": 1346865441719,
  "tags": [ "Office","Zurich","322","EVRYTHNG" ],
  "name": "Office-322",
  "description": "The collection of all Thngs in office 322"
}

Read All Collections

Read all available collections. The result may be paginated if there are more than 30 items.

GET /collections
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/collections'
operator.collection().read().then(console.log);
List<Collection> collections = apiManager.collectionService().collectionsReader().execute();
for(Collection collection : collections) {
    System.out.println(collection.getId());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UmSc8WnPeXswtKRwwgkqBqHh",
    "createdAt": 1494410670561,
    "updatedAt": 1494836856606,
    "name": "My Collection",
    "collections": [
      "UmSyPf5RBg8RtpRaag9F9s3b"
    ]
  }
]

Update a Collection

Update a collection's fields with new data. Nested fields such as tags are replaced entirely with the value in the payload. The response payload is the complete updated collection document.

Note

There is a limit of 10,000 Thngs updated per API call on collections. If your collection contains more than 10,000 elements you should consider an iterative solution.

PUT /collections/:collectionId
Authorization: $OPERATOR_API_KEY

CollectionDocument (subset)
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/collections/U2a4AsGtqerbcWD6qhYGfb5d' \
  -d '{
    "name": "New Collection Name",
    "description": "New Collection Description",
  }'
const collectionId = 'UhQMMnGQbxnteaSDp7G8Fynn';

const collectionUpdate = {
  name: 'New Collection Name',
  description: 'New Collection Description'
};

// in a single request
user.collection(collectionId).update().then(console.log);

// or on the entity itself
user.collection(collectionId).read().then((collection) => {
  collection.update(collectionUpdate).then(console.log);
});
String collectionId = "U2a4AsGtqerbcWD6qhYGfb5d";

Collection collection = new Collection();
collection.setName("New Collection Name");
collection.setDescription("Updated collection description");
collection = apiManager.collectionService().collectionUpdater(collectionId, collection).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "U2a4AsGtqerbcWD6qhYGfb5d",
  "createdAt": 1474984969259,
  "updatedAt": 1474984989915,
  "name": "New Collection Name",
  "description": "New Collection Description"
}

Delete a Collection

Delete a single collection by ID.

Note

If the collection contains more than 500 Thngs, these will need to be removed from the collection (but not deleted themselves) before the collection may be deleted itself.

DELETE /collections/:collectionId
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/collections/U2a4AsGtqerbcWD6qhYGfb5d'
const collectionId = 'U2a4AsGtqerbcWD6qhYGfb5d';

// in a single request
operator.collection(collectionId).delete();

// or on the entity itself
operator.collection(collectionId).read().then((collection) => {
  collection.delete();
});
String collectionId = "U2a4AsGtqerbcWD6qhYGfb5d";

apiManager.collectionService().collectionDeleter(collectionId).execute();
HTTP/1.1 200 OK

Read All Thngs in a Collection

Get the list of all the thngs in a collection can be retrieved via a GET on the /thngs resource of a collection. The result may be paginated if there are more than 30 items.

GET /collections/:collectionId/thngs
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/collections/U2wGPSspbrqFcKxdVtM8yhgt/thngs'
const collectionID = 'U2wGPSspbrqFcKxdVtM8yhgt';

// In a single request
user.collection(collectionId).thng().read().then(console.log);

// Or on the resource itself
user.collection(collectionId).read().then((collection) => {
  collection.thng().read().then(console.log);
});
String collectionId = "U2wGPSspbrqFcKxdVtM8yhgt";

List<Thng> thngs = apiManager.collectionService().thngsReader(collectionId).execute();
for (Thng t : thngs) {
    System.out.println(t.toString());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "U2wGPSspbrqFcKxdVtM8yhgt",
    "createdAt": 1492606257456,
    "updatedAt": 1496752159725,
    "name": "Rubiks Cube - Recommended",
    "description": "Updated Thng description.",
    "product": "UFKE9nHBBg8atKaawgVrKKbs",
    "collections": [
      "U2wGPSspbrqFcKxdVtM8yhgt"
    ]
  }
]

Read a Collection

Read a single collection by its ID.

GET /collections/:collectionId
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/collections/U2wGPSspbrqFcKxdVtM8yhgt'
const collectionId = 'U2wGPSspbrqFcKxdVtM8yhgt';

operator.collection(collectionId).read().then(console.log);
String collectionId = "U2wGPSspbrqFcKxdVtM8yhgt";

Collection collection = apiManager.collectionService().collectionReader(collectionId).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id":"U2wGPSspbrqFcKxdVtM8yhgt",
  "createdAt":1346865128086,
  "updatedAt":1347024162647,
  "name": "Office-322",
  "description": "The collection of all thngs in office 322"
  "customFields": {
    "insured": "true"
  },
  "tags": [ "Office", "Zurich", "322", "EVRYTHNG" ]
}

Add Thngs to a Collection

Thngs can be added to a collection by PUTing an array with their respective thngIds to the /thngs.

Note

The maximum number of Thngs that can be added to a collection is 10,000 per request.

PUT /collections/:collectionId/thngs
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

[ ThngID, ... ]
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/collections/UhQMMnGQbxnteaSDp7G8Fynn/thngs' \
  -d '[
    "UBMpmseRseKRBaDYKg5ychya", 
    "UemSgmdP8BpwT4N9sHbAUd5q"
  ]'
const collectionId = 'UhQMMnGQbxnteaSDp7G8Fynn';

const thngs = [
  'UBMpmseRseKRBaDYKg5ychya',
  'UemSgmdP8BpwT4N9sHbAUd5q'
];

// in a single request
appUser.collection(collectionId).thng().update(thngs).then(console.log);

// or on the resource itself
appUser.collection(collectionId).read().then((collection) => {
  collection.thng().update(thngs).then(console.log);
});
String collectionId = "UhQMMnGQbxnteaSDp7G8Fynn";

apiManager.collectionService().thngsAdder(collectionId, thngIdList).execute();
HTTP/1.1 200 OK

You can also add Thngs to collections as they are created, by including an array of IDs of collections the Thng should be added to in the creation request:

POST /thngs
Authorization: $OPERATOR_API_KEY
Content-Type: application/json

{
  "name": "Thng in Collection",
  "collections": [
    "UHNfNCpMeD8RQKRwwE96aedk"
  ]
}
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "U4rWsCfnBg8RQKwRak2hUtrq",
  "createdAt": 1523967322548,
  "updatedAt": 1523967322548,
  "name": "Thng in Collection",
  "collections": [
    "UHNfNCpMeD8RQKRwwE96aedk"
  ]
}

Remove a Thng from a Collection

Thngs can be removed from within a collection, by sending a DELETE to their ID within the :collectionID/thngs sub-resource of a collection.

Note

There is a limit of 500 Thngs deleted per API call on collections. If your collection contains more than 500 elements you should consider an iterative solution.

DELETE /collections/:collectionId/thngs/:thngId
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/collections/UhQMMnGQbxnteaSDp7G8Fynn/thngs/UF6qwDbaVDPwQKRwagmnqyqs'
const collectionId = 'UhQMMnGQbxnteaSDp7G8Fynn';
const thngId = 'UF6qwDbaVDPwQKRwagmnqyqs';

// in a single request
operator.collection(collectionId).thng(thngId).delete();

// or on the resource itself
operator.collection(collectionId).read().then((collection) => {
  collection.thng(thngId).delete();
});
String collectionId = "UhQMMnGQbxnteaSDp7G8Fynn";
String thngId = "UF6qwDbaVDPwQKRwagmnqyqs";

apiManager.collectionService().thngRemover(collectionId, thngId).execute();
HTTP/1.1 200 OK

Remove All Thngs from a Collection

All Thngs within a collection can be removed by sending a DELETE to the /thngs resource of a collection.

DELETE /collections/:collectionId/thngs
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/collections/U2a4AsGtqerbcWD6qhYGfb5d/thngs'
const collectionId = 'U2a4AsGtqerbcWD6qhYGfb5d';

// in a single request
operator.collection(collectionId).thng().delete();

// or on the resource itself
operator.collection(collectionId).read().then((collection) => {
  collection.thng().delete();
});
String collectionId = "U2a4AsGtqerbcWD6qhYGfb5d";

apiManager.collectionService().thngsRemover(collectionId).execute();
HTTP/1.1 200 OK

Read All Collections in a Collection

The list of all the collections in a collection can be retrieved via a GET on the /collections sub-resource of a collection. The result may be paginated if there are more than 30 items.

GET /collections/:collectionId/collections
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/collections/U2a4AsGtqerbcWD6qhYGfb5d/collections'
const collectionId = 'U2a4AsGtqerbcWD6qhYGfb5d';

operator.collection(collectionId).collection().read().then(console.log);
String collectionId = "U2a4AsGtqerbcWD6qhYGfb5d";

List<Collection> collections = apiManager.collectionService().childrenCollectionsReader(collectionId).execute();
for(Collection child : collections) {
    System.out.println(child.toString());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UmSyPf5RBg8RtpRaag9F9s3b",
    "createdAt": 1494410672569,
    "updatedAt": 1494836852529,
    "name": "New collection name",
    "description": "New collection description",
    "collections": [
      "U2a4AsGtqerbcWD6qhYGfb5d"
    ]
  }
]

Add Collections to a Collection

Child collections can be added to a collection by POSTing an array with their respective IDs to the /collections endpoint.

POST /collections/:collectionId/collections
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

[ CollectionID, ... ]
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/collections/U2amsb7M7a2bD4xD9mEVDdWf/collections' \
  -d '[
    "UFwG8xsAb7qkcKbdeQMscDer", 
    "U2a4AsGtqerbcWD6qhYGfb5d"
  ]'
const collectionId = 'U2amsb7M7a2bD4xD9mEVDdWf';

// The child collections to add to collection
const childCollectionIds = [ 
  'UFwG8xsAb7qkcKbdeQMscDer', 
  'U2a4AsGtqerbcWD6qhYGfb5d' 
];

operator.collection(collectionId).read().then((collection) => {
  collection.collection().create(childCollectionIds).then(console.log);
});
String collectionId = "U2amsb7M7a2bD4xD9mEVDdWf";

HashSet<String> childCollectionSet = new HashSet<String>();
childCollectionSet.add("UFwG8xsAb7qkcKbdeQMscDer");
childCollectionSet.add("U2a4AsGtqerbcWD6qhYGfb5d");

apiManager.collectionService().childrenCollectionsAdder(collection1Id, childCollectionSet).execute();
HTTP/1.1 200 OK

Remove a Collection from a Collection

Collections can be removed from within a collection, by sending a DELETE to their ID within the :collectionId/collections sub-resource of a collection.

DELETE /collections/:collectionId/collections/:childCollectionId
Authorization: $OPERATOR_API_KEY
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/collections/UhQMMnGQbxnteaSDp7G8Fynn/collections/U2amsb7M7a2bD4xD9mEVDdWf'
const parentCollectionId = 'UhQMMnGQbxnteaSDp7G8Fynn';
const childCollectionId = 'U2amsb7M7a2bD4xD9mEVDdWf';

operator.collection(childCollectionId).read().then((collection) => {
  collection.collection(parentCollectionId).delete();
});
String parentCollectionId = "UhQMMnGQbxnteaSDp7G8Fynn";
String childCollectionId = "U2amsb7M7a2bD4xD9mEVDdWf";

apiManager.collectionService().childCollectionRemover(parentCollectionId, childCollectionId).execute();
HTTP/1.1 200 OK

Remove all Collections from a Collection

All collections within a collection can be removed by sending a DELETE to the /collections resource of a collection.

DELETE /collections/:collectionId/collections
Authorization: $OPERATOR_API_KEY
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/collections/UhQMMnGQbxnteaSDp7G8Fynn/collections'
const parentCollectionId = 'UhQMMnGQbxnteaSDp7G8Fynn';

operator.collection(parentCollectionId).collection().delete();
String parentCollectionId = "UhQMMnGQbxnteaSDp7G8Fynn";

apiManager.collectionService().childrenCollectionsRemover(parentCollectionId).execute();
HTTP/1.1 200 OK
Suggest Edits

Identifier Recognition

 

EVRYTHNG offers an Identifier Recognition service through the REST API. Developers use this resource to identify barcodes in images, and any linked products or Thngs linked to those codes.

Any Application and Operator API key can POST an image, and if a product/Thng redirection or barcode matches the image, the service returns information about the matches made. This includes any redirection information set up for the resource that matched the image recognition query.

Walkthrough

For a complete walkthrough of the process of utilizing product recognition, read Real-time Web Product Scanning


API Status
Stable:
/scan/identifications
tn.gg/redirections/:shortId/ir
Preview:
/scan/identifications when method=ocr


Enabling Recognition

To enable recognition of a specific type of barcode, include the appropriate product identifier as an item in the identifiers field in the Thng or product to be recognised at scan time.

This can be done through the REST API, or via the Dashboard. The value of the key should be the numerical value encoded within the barcode itself. For example:

{
  "name": "Thng with barcode",
  "description": "An example Thng with a barcode identifier to aid in barcode recognition",
  "tags": [ "object", "scan-friendly", "barcode" ],
  "identifiers: {
    "ean_8": "96385074"
  }
}

Alternatively, if the scanned image is a Thng or product redirection QR code, you can also use the encoded URL as the value field, where applicable. QR codes generated when adding a redirection for a given Thng or product will also be matched independently of the identifiers listed.


Performing a Scan or Identification

Scanning an image is performed by making a POST request to /scan/identifications through the API, or using the scan() method in the evrythng.js SDK. The filter query parameter specified dictates which types of codes are searched for or recognition methods are attempted with the supplied image payload.

Similarly, a GET request to the same resource will attempt to find any products or Thngs visible to the authenticating Application or Operator API Key with a code containing the value query parameter value. For example, a QR code with tn.gg redirection to a product would match a value=https://tn.gg/yyZZ1nAh query parameter value.

See Identify from an Image or Read an Identifier's Product or Thng for example requests.


Filter Format

The filter query parameter can contain the following items:

  • method - String
    The scanning method to use.

  • type - String
    The type of identifier to identify.

You can optionally also include the following parameters in the URL:

  • perPage - Integer
    Specify how many items to return per page of results.

  • debug - Boolean
    Set to true to view extra information used to measure performance.

Important

The filter text must be URL encoded, similar to other Platform filters.

The different types of methods and identifier types are shown in the table below:

Methods
Types

ocr - Optical character recognition

text - Text recognition.

ir - Image recognition

image - Recognition based on pre-submitted images.

1d - One dimensional barcodes

codabar - Codabar
code_11 - Code 11
code_39 - Code 39
code_93 - Code 93
ean_8 - EAN-8
ean_13 - EAN-13
industr_25 - Code 25 Industrial
itf - ITF-14
rss_14 - GS1 DataBar (RSS-14)
rss_expanded - DataBar Expanded (RSS Expanded)
rss_limited - DataBar Limited (RSS Limited)
upc_a - UPC-A
upc_e - UPC-E

2d - Two dimensional barcodes

dm - DataMatrix
qr_code - QR Code

Using Multiple Types of Recognition

Both the method and type fields of the filter parameter may be specified as lists containing multiple items from their respective available values. For example, to use both OCR text recognition and QR code recognition:

POST /scan/identifications?filter=method=<method1>,<method2>&type=<type1>,<type2>
Content-Type: application/json
Authorization: $APPLICATION_API_KEY
curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/scan/identifications?filter=method%3D1d%2C2d%26type%3Dqr_code%2Cdm' \
  -d '{
    "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAA..."
  }'
// Video stream
app.scanStream({
  filter: { method: '2d', type: 'qr_code' },
  containerId: 'stream_container',
}).then(console.log);

// Single photo
app.scan({
  filter: {
    method: ['2d', 'ocr'],
    type: ['qr_code', 'text']
  }
}).then(console.log);

In the case that multiple types are specified, the method may be omitted:

POST /scan/identifications?filter=type=<type1>,<type2>
Content-Type: application/json
Authorization: $APPLICATION_API_KEY
curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/scan/identifications?filter=type%3Dqr_code%2Cdm' \
  -d '{
    "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAA..."
  }'
app.scan({
  filter: {
    type: ['text', 'qr_code']
  }
}).then(console.log);

Lastly, it is possible to attempt to identify any and all codes in the image by omitting the filter query parameter entirely.


Matching and Response

When a code type matching the filter specified is found in the image, the Identifier Recognition API looks for a Thng/product that is visible to the API key that performed the call (i.e.: in the same scope).

The response is an array containing metadata and a set of matching results, if any were found. If there were no results, or an incompatible combination of method and type were specified, an empty array will be returned. If the scan was performed on behalf of a user, their object will also be included, allowing extra functionality such as Scan actions. An example is shown below:

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "results": [
      {
        "redirections": [
          "https://tn.gg/Q9Wqcg4w"
        ],
        "product": {
          "id": "UYKNDMGcswyFBdf6wr7M5Erm",
          "properties": {},
          "fn": "Test Product",
          "name": "Test Product",
          "identifiers": {}
        }
      }
    ],
    "meta": {
      "method": "2d",
      "score": 100,
      "value": "https://tn.gg/Q9Wqcg4w",
      "type": "qr_code"
    }
  }
]

Data Fields

  • results - Object array
    Array of identification results, containing the matching Thng/product and any redirections associated with it.

  • meta - Object
    Object containing metadata about the identification operation. Not intended for business logic use.

    • meta.method - String
      The method used to identify the product/Thng.

    • meta.score - Number
      Confidence score of the results for the ir method, or 100 for one or more matches for the other method values, else 0 if no Thngs or products were found.

    • meta.value - String
      The actual value encoded within the identifier. Can be used with a GET request to retrieve the associated Thng/product.

    • meta.type - String
      The type used to identify the Thng/product.


Payload Sources

The /scan/identifications endpoint accepts JPG and PNG images as a file upload or Base64-encoded image data as a string.

File Upload

You can upload a file either from a file browser or a direct camera capture on mobile devices. The scanthng.js library includes this functionality as part of its API. When the scan() method is invoked, the device-specific native dialog for choosing a file or capturing from a camera is shown to the user. See below for examples.

Note

On desktops or laptops, we suggest using the Say Cheese library to capture from the user's webcam, if available.

Base64 Data

As an alternative to uploading a file through evrythng.js, Base64 image data may also be submitted in the request body. The image must be encoded in a string containing the MIME type header before the actual image data (i.e.: "data:{content-type},...{Base64 data}...") and be nested inside a JSON object with the image key. A truncated example is shown below:

{
  "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCARXhpZgAAKg..."
}

Example File Uploads

File Upload

EVT.use(Scan);

const app = new EVT.App(APPLICATION_API_KEY);

// Launch image capture or file upload for image to scan
// The 'filter' chosen here will look for a 2D QR code
app.scan({
  filter: { method: '2d', type: 'qr_code' }
})
  .then((response) => {
    // Do something on success
  })
  .catch((error) => {
    // Do something on error
  });

Base64 Data

POST /scan/identifications?filter=method%3D<method>%26type%3D<type>
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

{
  "image": Base64 Data
}
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/scan/identifications?filter=method%3D<method>%26type%3D<type>' \
  -d '{
    "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCARAAKg..."
  }'
EVT.use(Scan);

const app = new EVT.App(APPLICATION_API_KEY);
const data = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...';
const options = { filter: 'method=2d&type=qr_code' };

app.scan(data)
  .then((response) => {
    // Do something with the result, such as a scan action
  }).catch((error) => {
    // Do something on error
  });

Identify from an Image

Important

The filter text must be URL encoded, similar to other Platform filters.

When a request is made to the /scan/identifications endpoint with the POST method, the image is analysed according to the filter query string provided, and one or more matches to products/Thngs are produced if they list the matching identifiers values.

POST /scan/identifications?filter=method=<method>&type=<type>
Content-Type: application/json
Authorization: $APPLICATION_API_KEY

{
  "image": Base64 Data
}
# The `image` value below has been truncated for brevity.

curl -H "Content-Type: application/json" \
  -H "Authorization: $APPLICATION_API_KEY" \
  -X POST 'https://api.evrythng.com/scan/identifications?filter=method%3D2d%26type%3Dqr_code' \
  -d '{
    "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAA..."
  }'
app.scan({
  filter: { method: '2d', type: 'qr_code' }
})
  .then(console.log)
  .catch((error) => {
    // Do something on error
  });
const request = require('request');

const APPLICATION_API_KEY = 'xnDkdhezgJMnx6fGr4xMAxzPJpgM3xc0sbf...';

const FILTER = 'method=2d&type=qr_code';
const BASE_64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAA...';

request({
  url: `https://api.evrythng.com/scan/identifications?filter=${FILTER}`,
  method: 'POST',
  headers: { Authorization: APPLICATION_API_KEY },
  json: { image: BASE_64 }
}, (err, response, body) => {
  if(err) {
    console.log(err);
    return;
  }

  console.log(JSON.stringify(body, null, 2));
});

Read an Identifier's Product or Thng

If a value has already been extracted from an image via the POST /scan/identifications endpoint, you can read the associated product or Thng with a GET request containing a filter specifying the type of the identifier.

Note

The type parameter must be specified with the submitted value for the identification to succeed.

GET /scan/identifications?filter=type=<type>&value=<value>
Authorization: $APPLICATION_API_KEY
curl -H "Authorization: $APPLICATION_API_KEY" \
  -X GET 'https://api.evrythng.com/scan/identifications?filter=type%3Dqr_code%26value%3Dhttps://tn.gg/yyZZ1nAh'
// Get identification info for pre-obtained value 'https://tn.gg/Q9Wqcg4w'
app.identify({
  filter: { type: 'qr_code', value: 'https://tn.gg/Q9Wqcg4w' }
})
  .then(console.log)
  .catch((error) => {
    // Do something on error
  });
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "results": [
      {
        "redirections": [
          "https://tn.gg/yyZZ1nAh"
        ],
        "product": {
          "id": "UYKNDMGcswyFBdf6wr7M5Erm",
          "properties": {},
          "fn": "Test Product",
          "name": "Test Product",
          "identifiers": {}
        }
      }
    ],
    "meta": {
      "method": "2d",
      "score": 100,
      "value": "https://tn.gg/yyZZ1nAh",
      "type": "qr_code"
    }
  }
]

Create an IR Reference Image

Upload a local file as a reference image for a given redirection short ID.

POST https://tn.gg/redirections/:shortId/ir
Content-Type: image/jpeg
Authorization: $OPERATOR_API_KEY

File
curl -H "Authorization: $OPERATOR_API_KEY" \
  'https://tn.gg/redirections/G53eYMM3/ir' \
  -F 'file=@pack-front.jpg'
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "5ab9159fa898950028b54a55",
  "name": "5ab90ecbaedf0700266aa412_b98e27f0-310c-11e8-8461-db50a78858ff",
  "thumb60": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_cfc010020ae357f0f9dc0e64334bcf57_60.jpg",
  "thumb120": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_cfc010020ae357f0f9dc0e64334bcf57_120.jpg",
  "file": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_cfc010020ae357f0f9dc0e64334bcf57.jpg"
}

Read all IR Reference Images

Read all uploaded reference images for a given short ID.

GET https://tn.gg/redirections/:shortId/ir
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET https://tn.gg/redirections/G53eYMM3/ir 
HTTP/1.1 200 OK

[
  {
    "id": "5ab90eccaedf0700266aa413",
    "name": "5ab90ecbaedf0700266aa412_a7c735b0-3108-11e8-b46e-c7973462d6ac",
    "thumb60": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_97d0df0d6e0a67d0b27cc8affce9dc40_60.jpg",
    "thumb120": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_97d0df0d6e0a67d0b27cc8affce9dc40_120.jpg",
    "file": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_97d0df0d6e0a67d0b27cc8affce9dc40.jpg"
  },
  {
    "id": "5ab9141d612c11003155af7d",
    "name": "5ab90ecbaedf0700266aa412_d31ffb90-310b-11e8-84a2-852d87264559",
    "thumb60": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_0f996323948b67b8c07d7e172f795ad9_60.jpg",
    "thumb120": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_0f996323948b67b8c07d7e172f795ad9_120.jpg",
    "file": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_0f996323948b67b8c07d7e172f795ad9.jpg"
  },
  {
    "id": "5ab9148d98d2f700221d7629",
    "name": "5ab90ecbaedf0700266aa412_15eaad30-310c-11e8-a6fe-2d2710455ba9",
    "thumb60": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_9cd4eecf06a1af38aa39bd3f11ad35e6_60.jpg",
    "thumb120": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_9cd4eecf06a1af38aa39bd3f11ad35e6_120.jpg",
    "file": "https://prod-scan-app-bucket-1x12op27qs6xd.s3.amazonaws.com/upload_9cd4eecf06a1af38aa39bd3f11ad35e6.jpg"
  }
]

Delete an IR Reference Image

Remove a previously uploaded reference image by id.

DELETE https://tn.gg/redirections/:shortId/ir/:id
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE https://tn.gg/redirections/G53eYMM3/ir/5ab917fea898950028b54a56
HTTP/1.1 200 OK

Scan Actions

A Scan action created upon a successful recognition generates valuable contextual data which can be used for business rules/decision making and data insights analysis. For example: geolocation; browser and device type; anonymous user ID.

Creating a Scan action can done using the result returned by scan() with the evrythng.js SDK. An example is shown below:

Note

Since an action cannot be created with an Application API Key, the createAnonymousUser: true option is required in order to be able to create a Scan action as an Application User. Alternatively, a regular Application User API Key can also be used.

app.scan({
  filter: { method: '2d', type: 'dm' },
  createAnonymousUser: true,
})
  .then((response) => {
    // Create a Scan action as the anonymous user for the first result
    const result = response[0].results[0];  
    return result.thng.action('scans').create();
  })
  .catch((error) => {
    // Do something on error
  });

With this option enabled, you will receive a lot more useful data items, shown in the example below. Most notable are the addition of the location, and createdBy... items, which can be used for analysis and decision making when aggregated across a large number of scans.

[
  {
    "id": "UkAsQqTWN2y2tfwVkyBKykws",
    "createdAt": 1480522789344,
    "timestamp": 1480522789344,
    "type": "scans",
    "user": "UFAsQqTRtEf5FpRekYC5CgKg",
    "location": {
      "latitude": 51.5142,
      "longitude": -0.0931,
      "position": {
        "type": "Point",
        "coordinates": [ -0.0882956, 51.5303183 ]
      }
    },
    "locationSource": "geoIp",
    "createdByProject": "U2As9WsMthW5F5aeFECpCeDs",
    "createdByApp": "UFUstWQVQEC5FpRe2EWpWBhf",
    "product": "UFd8t2aaN2y2tCwBFTepTgEs"
  }
]

Redirections

Once an identifier has been recognized, the results can be used to redirect the user to a pre-set destination according to any redirections attached to the product/Thng associated with the result. For example:

// Perform a scan for identifiers
app.scan({
  filter: { method: '2d', type: 'qr_code' },
  createAnonymousUser: true,
})
  .then((response) => {
    // Redirect to the first redirection set on the resource
    const result = response[0].results[0];  
    app.redirect(result.redirections[0]);
  })
  .catch((error) => {
    // Do something on error
  });

Error Codes

The table below details the error codes that may be returned by the Identifier Recognition API:

Error Code
Descriptions

404

Image not recognized
Image does not contain a valid identifier

403

Access denied: Image recognition not permitted with this API key

400

Alpha transparency not supported
Duplicate images are not allowed

503

Service unavailable


Known Issues

  • Denying access to location in Firefox, IE11, and Edge browsers can cause issues with scanthng.js. Make sure to guide users to always accept the request for location data.

  • Using a web app or page in Safari Incognito mode can cause issues with scanthng.js. Apps should display a message instructing users to not use Safari Incognito mode.

The File API manages storage and retrieval of files. Only Operators can perform these requests. An EVRYTHNG file resource only contains the metadata for the file (name, type, etc.). The actual file itself is uploaded separately as part of the workflow detailed below.

The process for storing a file within the Platform consists of two steps:

  1. Creating a FileDocument metadata resource detailing the file's format.
  2. Uploading the file itself to the URL specified in the created FileDocument in a separate request.

API Status
Stable:
/files
/files/:fileId


FileDocument Data Model

A FileDocument holds information about a file stored on a remote platform. This includes signed upload and download URLs for a file, and also whether the file has 'private' or 'public' access on remote storage.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.tags (array of string)
    Array of string tags associated with this resource.

.uploadUrl (string, read-only)
    The URL to upload file data to with an HTTP `PUT` request. 
    Will expire after 30 mins.

.contentUrl (string, read-only)
    The URL the file is available at for download.

.name (string)
    Name of the file. This is unique to the account, allowing a 
    file to be overwritten.

.type (string)
    The MIME type of the file. Must match the Content-Type 
    header used when uploading the file content.

.privateAccess (boolean)
    A boolean flag indicating whether a file should have 
    `private` or `public` access on remote storage.

.size (integer, read-only)
    The size of the uploaded file in bytes.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object containing remote file metadata.",
  "properties": {
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "uploadUrl": {
      "type": "string",
      "description": "The URL to upload file data to with an HTTP `PUT` request. Will expire after 30 mins.",
      "readOnly": true
    },
    "contentUrl": {
      "type": "string",
      "description": "The URL the file is available at for download.",
      "readOnly": true
    },
    "name": {
      "type": "string",
      "description": "Name of the file. This is unique to the account, allowing a file to be overwritten."
    },
    "type": {
      "type": "string",
      "description": "The MIME type of the file. Must match the Content-Type header used when uploading the file content."
    },
    "privateAccess": {
      "type": "boolean",
      "description": "A boolean flag indicating whether a file should have `private` or `public` access on remote storage."
    },
    "size": {
      "type": "integer",
      "description": "The size of the uploaded file in bytes.",
      "readOnly": true
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "name", "tags" ]
}
{
  "id": "UkHsQB7C6msEhqaaR2tsQbWh",
  "createdAt": 1487860949665,
  "updatedAt": 1487860949665,
  "uploadUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/example-file.js?...",
  "contentUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/example-file.js",
  "size": 35862,
  "name": "example-file.js",
  "type": "application/javascript",
  "privateAccess": false
}

See also: ScopesDocument


Create Remote File Metadata

Use this endpoint to create a metadata record for a file to be uploaded. This operation is the basis for a remote file upload. A successful HTTP POST will create a FileDocument record with a unique ID and a transient uploadUrl field.

This signed uploadUrl can then be used by a client with an HTTP PUT request to do the actual upload to remote storage. The uploadUrl will expire after 30 minutes. The input payload to this endpoint should also contain a setting for the privateAccess field to indicate whether the file should have 'private' or 'public' access on remote storage.

POST /files
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

FileDocument
evrythng files create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/files' \
  -d '{
    "name": "my_file1.txt",
    "type": "text/plain",
    "tags": [ "files" ],
    "privateAccess": false
  }'
const file = {
  name: 'my_file1.txt',
  type: 'text/plain',
  tags: [ 'files' ],
  privateAccess: false
};

operator.file().create(file).then(console.log);
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/files/U2k9enU2BD8RQKaaagME5dFn

{
  "id": "U2k9enU2BD8RQKaaagME5dFn",
  "createdAt": 1485785656730,
  "tags": [
    "files"
  ],
  "updatedAt": 1485785656730,
  "uploadUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/my_file1.txt?AWSAccessKeyId=AKIAID2MOF7RYNLLMH7Q&Expires=1485787456&Signature=YWBUFgcyCKfcTxEg9tzxAxmvP%2FU%3D",
  "name": "my_file1.txt",
  "type": "text/plain",
  "privateAccess": false
}

Read Metadata for All Remote Files

Use this endpoint to get a list of FileDocuments associated with this account ID. The retrieved file metadata will have (among other attributes), a file's unique ID, and a transient contentUrl field which can be used to download the actual file represented by the resource using an HTTP GET request. The value of the privateAccess boolean field will indicate whether the file has 'public' or 'private' access on remote storage. The result may be paginated if there are more than 30 items.

Important

If the privateAccess flag is set to true, then the contentUrl will expire after 30 minutes.

This endpoint also supports filtering by name and tags filters. Details of filters can be found on the Filters page.

GET /files
Authorization: $OPERATOR_API_KEY
evrythng files list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/files"
operator.file().read().then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UkYqry34eDswtKawaYMqwfbr",
    "createdAt": 1484575386979,
    "tags": [
      "files"
    ],
    "updatedAt": 1484575386979,
    "uploadUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/test.txt?AWSAccessKeyId=AKIAID2MOF7RYNLLMH7Q&Expires=1485788741&Signature=eyJvv7wFCl8AFaG9G%2BDYapUdoZc%3D",
    "contentUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/test.txt",
    "size": 67,
    "name": "test.txt",
    "type": "text/plain",
    "privateAccess": false
  }
]

Read Remote File Metadata by ID

Use this endpoint to get metadata for a specific remote file by ID. The fileId path parameter should be the value returned when the FileDocument was created.

The retrieved file metadata will have (among other attributes), a transient contentUrl field which can be used to download the physical file using an HTTP GET request. The value of the privateAccess boolean field will indicate whether the file has 'public' or 'private' access on remote storage.

GET /files/:fileId
Authorization: $OPERATOR_API_KEY
evrythng files $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/files/UFm5cMg7Bgsat5aawFS4nhHt'
const fileId = 'UFm5cMg7Bgsat5aawFS4nhHt';

operator.file(fileId).read().then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UFm5cMg7Bgsat5aawFS4nhHt",
    "createdAt": 1484575386979,
    "tags": [
      "files"
    ],
    "updatedAt": 1484575386979,
    "uploadUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/test.txt?AWSAccessKeyId=AKIAID2MOF7RYNLLMH7Q&Expires=1485788741&Signature=eyJvv7wFCl8AFaG9G%2BDYapUdoZc%3D",
    "contentUrl": "https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg39QCy9dsSddN8xhwnb/test.txt",
    "size": 67,
    "name": "test.txt",
    "type": "text/plain",
    "privateAccess": false
  }
]

Delete Remote File by ID

Use this endpoint to delete a remote file by ID. The fileId path parameter should be the id value returned when the FileDocument was created.

Important

This endpoint will physically delete the file on remote storage, and will also remove the file's metadata record on the platform.

DELETE /files/:fileId
Authorization: $OPERATOR_API_KEY
evrythng files $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/files/UFm5cMg7Bgsat5aawFS4nhHt'
const fileId = 'UFm5cMg7Bgsat5aawFS4nhHt';

operator.file(fileId).delete().then(() => console.log('Deleted'));
HTTP/1.1 200 OK

File Upload Workflow

In order to upload a file you need to get a signed uploadUrl, which can then be used with an HTTP PUT request to perform a multipart or binary data upload.

Step 1: Create Remote File Metadata and note the uploadUrl in the response, including its query parameters.

Step 2: Perform an HTTP PUT request to the uploadUrl attribute, and specify the x-amz-acl header as private or public-read, depending on the file resource's privateAccess field. Make sure to also match the Content-Type also specified previously.

The example below shows uploading a text file to the Files API. For the cURL example, the --data-binary flag will also work for other files types, such as images.

PUT :uploadUrl
Content-Type: text/plain
x-amz-acl: public-read


- - - - - -WebKitFormBoundaryKJ2T3DyoTYBx6Byd
Content-Disposition: form-data; name="file"; filename="my_file.txt"
Content-Type: text/plain

My remote file text content


- - - - - -WebKitFormBoundaryKJ2T3DyoTYBx6Byd--
evrythng files $id upload $file-path $mime-type
curl -H "Content-Type: text/plain" \
  -H "x-amz-acl: public-read" \
  -X PUT 'https://s3.amazonaws.com/evtcdn_02/2/uf/UhpHrg3837hgdsSddN8xhwnb/thng-prod.png?AWSAccessKeyId=AKIHD8YH9F7RYNLLMH7Q&Expires=1486726308&Signature=op3MlVJ46HF53%2F%2BDRKqAV2cJtYM%3D' \
  --data-binary @my_file.txt
HTTP/1.1 200 OK

File Download Workflow

In order to download a previously uploaded remote file you need to get a contentUrl by performing an HTTP GET request with the file's ID. The contentUrl can then be used in a subsequent HTTP GET request to download the actual file.

Step 1: Retrieve remote file metadata by ID.

Step 2: Perform an HTTP GET request on the contentUrl using the correct value of the x-amz-acl header, either "private" or "public-read", that was used when the file was uploaded. You must also specify the correct Content-Type header for the uploaded file.

GET :contentUrl
Content-Type: text/plain
x-amz-acl: private (or public-read)
Suggest Edits

Locations

 

Some resource types include the notion of location, including Thngs and actions. The location of these resources can be used to give an indication of where they were created or updated.

If a location was specified with provided coordinates (see below for request examples), those will be used. If not, an automatic lookup from the request's IP address will be used to find approximate location instead.

All instances of a location follow the GeoJSON specification, specifically the Point data type, which expresses a single point on the world map with a pair of longitude, latitude coordinates.

Coordinate Order

When specifying coordinates in the EVRYTHNG API, make sure the ordering is latitude, then longitude. For example, Hammersmith in London would be -0.223391, 51.493209.


API Status
Stable: /thngs/:thngId/location


LocationDocument Data Model

.position (object)
    A GeoJSON Point object. The coordinate order is longitude, 
    then latitude.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.timestamp (integer, read-only)
    The time the location update occurred, or filled 
    automatically by the Platform if omitted.

.longitude (number)
    The longitude.

.latitude (number)
    The latitude.

.place (string)
    The place ID.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object representing a location.",
  "properties": {
    "position": {
      "type": "object",
      "description": "A GeoJSON Point object. The coordinate order is longitude, then latitude.",
      "properties": {
        "type": {
          "type": "string",
          "description": "The type of the point.",
          "enum": [ "Point" ]
        },
        "coordinates": {
          "type": "array",
          "description": "The point coordinates",
          "items": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          }
        }
      }
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "timestamp": {
      "type": "integer",
      "description": "The time the location update occurred, or filled automatically by the Platform if omitted.",
      "readOnly": true
    },
    "longitude": {
      "type": "number",
      "description": "The longitude."
    },
    "latitude": {
      "type": "number",
      "description": "The latitude."
    },
    "place": {
      "type": "string",
      "description": "The place ID.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$"
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "timestamp" ]
}
{
  "latitude": -37,
  "longitude": -179.3,
  "position": {
    "type": "Point",
    "coordinates": [
      -179.3,
      -37
    ]
  }
}

See also: ScopesDocument


Read a Thng's Location History

To access all the location updates for a thng, send a GET to the /location endpoint of the Thng.

GET /thngs/:thngId/location
Authorization: $OPERATOR_API_KEY
evrythng thngs $id location read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/thngs/U2a4AsGtqerbcWD6qhYGfb5d/location'
const thngId = 'U2a4AsGtqerbcWD6qhYGfb5d';

// in a single request
user.thng(thngId).location().read().then(console.log);

// or on the resource itself
user.thng(thngId).read().then((thng) => {
  thng.location().read().then(console.log);
});
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "timestamp":1347028945712,
    "createdAt":1347028945712,
    "position": {
      "type": "Point",
      "coordinates": [18.3,-36.4]
    }
  }
]

Update a Thng's Location

Just like properties, the location of a Thng can be updated at any time via the /location endpoint of the Thng. The payload must always be an array of LocationDocument objects, which allows you to send several locations (with different timestamps each) in a single request.

This is useful when a device wants to update a path cached over a certain period of time at once. An example would be a taxi that updates the whole set of locations it has been through once per hour instead of sending each GPS sensor reading individually.

Instead of specifying the location itself, it is also possible to specify a place to set the Thng's location.

PUT /thngs/:thngId/location
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

[ LocationDocument, ... ]
evrythng thngs $id location update $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/thngs/U2wm8b42MVNxTCX6MYDrRpyd/location' \
  -d '[{
      "position": {
        "type": "Point",
        "coordinates": [ -17.3, 36 ]
      }
    }, {
      "timestamp": 1347028945711,
      "position": {
        "type": "Point",
        "coordinates": [ -179.3, -37 ]
      }
    }]'
const thngId = 'U2wm8b42MVNxTCX6MYDrRpyd';

const update = [{
  position: {
    type: 'Point',
    coordinates: [ -17.3, 36 ]
  }
}, {
  timestamp: 1347028945711,
  position: {
    type: 'Point',
    coordinates: [ -179.3, -37 ]
  }
}];

// in a single request
user.thng(thngId).location().update(update).then(console.log);

// or on the resource itself
user.thng(thngId).read().then((thng) => {
  thng.location().update(update).then(console.log);
});
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "timestamp":1347550210375,
    "createdAt":1347028945712,
    "position": {
      "type": "Point",
      "coordinates": [-17.3, 36]
    }
  }, {
    "timestamp": 1347028945712,
    "createdAt": 1347028945712,
    "position": {
      "type": 'Point',
      "coordinates": [ -179.3, -37 ]
    }
  } 
]

Delete a Thng's Location History

Similar to properties, location updates are not individually identified, therefore the only way to delete them is by specifying a point in time before which all the updates will be deleted as a query param: ?to=Timestamp.

Important

If the ?to parameter is not specified, ALL location updates will be deleted for the Thng specified.

DELETE /thngs/:thngId/location[?to=Timestamp]
Authorization: $OPERATOR_API_KEY
# Deletes ALL location history
evrythng thngs $id location delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/thngs/U2wm8b42MVNxTCX6MYDrRpyd/location'
const thngId = 'U2wm8b42MVNxTCX6MYDrRpyd';

// in a single request
operator.thng(thngId).location().delete();

// or on the resource itself
operator.thng(thngId).read().then((thng) => thng.location().delete());
HTTP/1.1 200 OK

Set an Action's Location

When creating an action, specify the location property as a valid LocationDocument to set the action's location. An example is shown below:

{
  "thng": "UmAkSdqe69QVhswwRYNdbxna",
  "type": "scans",
  "location": {
    "position": {
  	  "type": "Point",
      "coordinates": [2.765852, 48.877675]
    }
  }
}

A place resource maps geographical coordinates to a known real-world location (a shop, an office, a park, etc.) where a product or Thng may be interacted within. It can be thought of as a defined fixed location, such as a manufacturing warehouse that every product will be manufactured at, as opposed to raw location that a Thng may have. As well as physical coordinates, places can contain conventional street address information, but these are not dynamically linked (coordinates bear no relation to the strings assigned to the address fields).

Places can be used to specify a Thng or action location instead of a set of physical coordinates. See the examples below to learn more.


API Status
Stable:
/places
/places/:placeId


PlaceDocument Data Model

.name (string)
    Friendly name of this resource.

.id (string, read-only)
    The ID of this resource.

.description (string)
    Friendly description of this resource.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.

.tags (array of string)
    Array of string tags associated with this resource.

.identifiers (object)
    Various identifiers (EPC, ISBN, etc.) as a JSON object with 
    one or more key-value pairs.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.position (object)
    A GeoJSON Point object. The coordinate order is longitude, 
    then latitude.

.icon (string)
    URL to an image representing the place.

.address (AddressDocument)

.longitude (number)
    The longitude.

.latitude (number)
    The latitude.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object describing a real physical place with an address.",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name of this resource."
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "description": {
      "type": "string",
      "description": "Friendly description of this resource."
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "identifiers": {
      "type": "object",
      "description": "Various identifiers (EPC, ISBN, etc.) as a JSON object with one or more key-value pairs."
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "position": { "$ref": "GeoJSONPointDocument" },
    "icon": {
      "type": "string",
      "description": "URL to an image representing the place."
    },
    "address": { "$ref": "AddressDocument" },
    "longitude": {
      "type": "number",
      "description": "The longitude."
    },
    "latitude": {
      "type": "number",
      "description": "The latitude."
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "name", "identifiers", "tags" ]
}
{
  "id": "U4w8qhpArDRSkRaRwFRUfnVe",
  "createdAt": 1510918067036,
  "customFields": {
    "address_book": "Known Addresses"
  },
  "tags": [
    "example",
    "place"
  ],
  "updatedAt": 1510918067036,
  "name": "Example place",
  "description": "An example place resource",
  "position": {
    "type": "Point",
    "coordinates": [
      5.625,
      21.94304553343818
    ]
  },
  "address": {
    "extension": "33",
    "street": "No Name",
    "postalCode": "CM875H",
    "city": "London",
    "county": "Essex",
    "state": "England",
    "country": "United Kingdom",
    "district": "Greater London",
    "buildingName": "The Moorings",
    "buildingFloor": "4",
    "buildingRoom": "Back Office",
    "buildingZone": "Light Industrial",
    "crossing1": "West and 5th",
    "crossing2": "Sixth and Memorial"
  },
  "identifiers": {
    "ean_13": "4389483927"
  },
  "latitude": 21.94304553343818,
  "longitude": 5.625
}

See also: ScopesDocument, AddressDocument


AddressDocument Data Model

.extension (string)
    The extension of the address.

.street (string)
    The street of the address.

.postalCode (string)
    The postal code of the address.

.city (string)
    The city of the address.

.county (string)
    The county of the address.

.state (string)
    The state of the address.

.country (string)
    The country of the address.

.countryCode (string)
    The country code of the address.

.district (string)
    The district of the address.

.buildingName (string)
    The building name of the address.

.buildingFloor (string)
    The building floor of the address.

.buildingRoom (string)
    The building room of the address.

.buildingZone (string)
    The building zone of the address.

.crossing1 (string)
    The first crossing of the address.

.crossing2 (string)
    The second crossing of the address.
{
  "type": "object",
  "description": "An object representing a street address.",
  "properties": {
    "extension": {
      "type": "string",
      "description": "The extension of the address."
    },
    "street": {
      "type": "string",
      "description": "The street of the address."
    },
    "postalCode": {
      "type": "string",
      "description": "The postal code of the address."
    },
    "city": {
      "type": "string",
      "description": "The city of the address."
    },
    "county": {
      "type": "string",
      "description": "The county of the address."
    },
    "state": {
      "type": "string",
      "description": "The state of the address."
    },
    "country": {
      "type": "string",
      "description": "The country of the address."
    },
    "countryCode": {
      "type": "string",
      "description": "The country code of the address."
    },
    "district": {
      "type": "string",
      "description": "The district of the address."
    },
    "buildingName": {
      "type": "string",
      "description": "The building name of the address."
    },
    "buildingFloor": {
      "type": "string",
      "description": "The building floor of the address."
    },
    "buildingRoom": {
      "type": "string",
      "description": "The building room of the address."
    },
    "buildingZone": {
      "type": "string",
      "description": "The building zone of the address."
    },
    "crossing1": {
      "type": "string",
      "description": "The first crossing of the address."
    },
    "crossing2": {
      "type": "string",
      "description": "The second crossing of the address."
    }
  }
}

Create a Place

Places are created using a POST request to the /places resource containing a JSON document.

POST /places
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

PlaceDocument
evrythng places create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST "https://api.evrythng.com/places" \
  -d '{
    "name": "Evrythng London Office",
    "position": {
      "type": "Point",
      "coordinates": [ -0.0882956, 51.5303183 ]
    },
    "address": {
      "extension": "Unit 4, 122",
      "street": "East Road",
      "postalCode": "N1 6FB",
      "city": "London",
      "countryCode": "GB"
    },
    "description": "London HQ",
    "icon": "https://evrythng.com/wp-content/themes/evrythng_v2.4/img/logo.svg",
    "tags": [
      "Office", "London"
    ],
    "identifiers": {
      "Place code": "KDL-46EX402AEP",
      "Place number": "027242784925"
    },
    "customFields": {
      "Internet": "Wi-Fi"
    }
  }'
const place = {
  name: 'Evrythng London Office',
  position: {
    type: 'Point',
    coordinates: [ -0.0882956, 51.5303183 ]
  },
  address: {
    'extension':'Unit 4, 122',
    'street':'East Road',
    'postalCode':'N1 6FB',
    'city':'London',
    'countryCode':'GB'
  },
  description: 'London HQ',
  icon: 'https://evrythng.com/wp-content/themes/evrythng_v2.4/img/logo.svg',
  tags: [ 'Office', 'London' ],
  identifiers: {
    'Placecode: 'KDL-46EX402AEP',
    'Placenumber: '027242784925'
  },
  customFields: {
    'Internet':'Wi-Fi'
  }
};

operator.place().create(place).then(console.log);
Place place = new Place();
place.setName("Evrythng London Office");
place.setPosition(new GeoJsonPoint(51.5008, -0.1247));
place.setTags(Arrays.asList("Office", "London"));
place = apiManager.placeService().placeCreator(place).execute();
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/places/UmBy2FXc6QQVhPaRaYNVErAb

{
  "id": "UmBy2FXc6QQVhPaRaYNVErAb",
  "createdAt": 1497453272208,
  "customFields": {
    "Internet": "Wi-Fi"
  },
  "tags": [
    "Office",
    "London"
  ],
  "updatedAt": 1497453272208,
  "name": "Evrythng London Office",
  "description": "London HQ",
  "icon": "https://evrythng.com/wp-content/themes/evrythng_v2.4/img/logo.svg",
  "position": {
    "type": "Point",
    "coordinates": [
      -0.0882956,
      51.5303183
    ]
  },
  "address": {
    "extension": "Unit 4, 122",
    "street": "East Road",
    "postalCode": "N1 6FB",
    "city": "London",
    "countryCode": "GB"
  },
  "identifiers": {
    "Place code": "KDL-46EX402AEP",
    "Place number": "027242784925"
  },
  "latitude": 51.5303183,
  "longitude": -0.0882956
}

Read a place

Perform a GET request on the /places resource including the place's ID to read it.

GET /places/:placeId
Authorization: $OPERATOR_API_KEY
evrythng places $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET "https://api.evrythng.com/places/UFR3PBUe7a2xDnbXQGYVnrGh"
const placeId = 'UFR3PBUe7a2xDnbXQGYVnrGh';

app.place(placeId).read().then(console.log);
String placeId = "UFR3PBUe7a2xDnbXQGYVnrGh";

Place place = apiManager.placeService().placesReader(placeId).execute();
System.out.println(place.getName());
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UFR3PBUe7a2xDnbXQGYVnrGh",
  "createdAt": 1416944292231,
  "tags":[ "Office", "London" ],
  "updatedAt": 1416944292231,
  "name": "Evrythng London Office",
  "description": "London HQ",
  "icon": "https://evrythng.com/wp-content/themes/evrythng_v2.4/img/logo.svg",
  "address": {
    "extension": "Unit 4, 122",
    "street": "East Road",
    "postalCode": "N1 6FB",
    "city": "London",
    "countryCode": "GB"
  }
}

Read All Places

Read all places associated with an account. The result may be paginated if there are more than 30 items.

GET /places
Authorization: $OPERATOR_API_KEY
evrythng places list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET "https://api.evrythng.com/places"
app.place().read().then(console.log);
List<Place> places = apiManager.placeService().placesReader().execute();
HTTP/1.1 200 OK
Content-Type: application/json

[ PlaceDocument, ... ]

Update a Place

PUT /places/:placeId
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

PlaceDocument (subset)
evrythng places $id update $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/places/UFR3PBUe7a2xDnbXQGYVnrGh' \
  -d '{
    "name": "My Updated Place",
    "description": "Updated description of the place."
  }'
const placeId = 'UFR3PBUe7a2xDnbXQGYVnrGh';

const update = {
  name: 'My Updated Place',
  description: 'Updated description of the place.'
};

operator.place(placeId).update(update).then(console.log);
String placeId = "UFR3PBUe7a2xDnbXQGYVnrGh";

// Read a place
Place place = apiManager.placeService().placeReader(placeId).execute();

// Update it
place.setName("My Updated Place");
place.setDescription("Updated description of the place.");
place = apiManager.placeService().placeUpdater(placeId, place).execute();
HTTP/1.1 200 Ok
Content-Type: application/json

{
  "id": "UFR3PBUe7a2xDnbXQGYVnrGh",
  "createdAt": 1433245674189,
  "updatedAt": 1433245917068,
  "name": "My Updated Place",
  "description": "Updated description of the place."
}

Delete a Place

To delete a place, simply send a DELETE to the place URL including the placeId. This action cannot be undone.

DELETE /places/:placeId
Authorization: $OPERATOR_API_KEY
evrythng places $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/places/UFR3PBUe7a2xDnbXQGYVnrGh'
const placeId = 'UFR3PBUe7a2xDnbXQGYVnrGh';

operator.place(placeId).delete().then(console.log);
String placeId = "UFR3PBUe7a2xDnbXQGYVnrGh";

apiManager.placeService().placeDeleter(placeId).execute();
HTTP/1.1 200 OK

Get All Places Near Origin

The following request returns a (paginated) list of all places within a radius of a longitude and latitude location origin, sorted by distance. The query parameters are:

  • lon - Double
    Longitude of the search origin.

  • lat - Double
    Latitude of the search origin.

  • maxDist - Integer
    The radius from the origin in kilometres.

GET /places?lat=:lat&lon=:lon&maxDist=:maxDist
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/places?lat=49.5&lon=127.4&maxDist=20'
app.place().read({
  params: {
    lat: 48.856,
    lon: 2.352,
    maxDist: 20
  }
}).then(console.log);
List<Place> places = apiManager.placeService().placesReader()
        .queryParam("lat", "48.856")
        .queryParam("lon", "2.352")
        .queryParam("maxDist", "20")
        .execute();
for(Place place : places) {
    System.out.println(place.getName());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UVEVNH4B8e5RgDUdmVr4Pxpc",
    "createdAt": 1416944292231,
    "tags": [ "Office","London" ],
    "updatedAt": 1416944292231,
    "name": "Evrythng London Office",
    "description": "London HQ",
    "icon": "https://evrythng.com/wp-content/themes/evrythng_v2.4/img/logo.svg",
    "address": {
      "street": "East Road",
      "city": "London",
      "countryCode": "GB"
    }
  }
]

Set a Thng's Location to a Place

It is possible to set a Thng's location to a place by adding a location history item with the place ID.

curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/thngs/UmCxU5c7BgPatpRawmWG7g6m/location' \
  -d '[{
    "place": "UkR2KhB7cGeMVmyENHxEXf2f"
  }]'
const thngId = 'UG4NgF9nBM8rtraRam9RreHg';
const update = [{
  place: 'UkR2KhB7cGeMVmyENHxEXf2f'
}];

user.thng(thngId).location().update(update).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "scopes": {
      "users": [],
      "projects": []
    },
    "timestamp": 1501160092412,
    "place": "UkR2KhB7cGeMVmyENHxEXf2f"
  }
]

Set an Action's Location to a Place

Similar to setting a Thng's location to a place, it is also possible to set an action's location to a place by its ID within the location object, and setting locationSource to "place".

{
  "type": "scans", 
  "thng": "UmCxU5c7BgPatpRawmWG7g6m", 
  "locationSource": "place", 
  "location": { 
    "place": "UkR2KhB7cGeMVmyENHxEXf2f"
  }
}
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "U3EG8cFyegPw9pwawEeAmpKd",
  "createdAt": 1501160066085,
  "timestamp": 1501160066085,
  "type": "scans",
  "location": {
    "place": "UkR2KhB7cGeMVmyENHxEXf2f",
    "latitude": 10.1,
    "longitude": 125.6,
    "position": {
      "type": "Point",
      "coordinates": [
        125.6,
        10.1
      ]
    }
  },
  "locationSource": "place",
  "context": {
    "city": "Dartford",
    "region": "England",
    "countryCode": "GB",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
    "timeZone": "Europe/London"
  },
  "thng": "UmCxU5c7BgPatpRawmWG7g6m"
}
 

Product resources are used to model a class of objects, and as such should contain information common to all instances. For example, a product resource could be used to describe a particular model of a physical product with specific characteristics (perhaps to match a specific SKU).

For example, of a specific TV model that has various properties such as a model number, a description, a brand, a category, etc. Each Thng instance of this TV product would reference the product that contains the SKU data, and instead only contain instance-level data, such as realtime state.

Products are useful to store properties or other data items that are common to a set of Thngs (so you don't need to replicate the model name or weight for thousands of Thngs that are individual instances of the same product). Therefore a product can be used to define the basic common properties of many Thngs.

In addition to specifying a product in an action, it is also possible to create an action through the product itself using aliased actions.


API Status
Stable:
/products
/products/:productId
/products/:productId/properties


ProductDocument Data Model

The product's data model used in our platform has been designed to be compatible with the h-product microformat, therefore it can easily be integrated with the h-product data model and applications supporting that microformat.

.name (string)
    Friendly name of this resource.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.activatedAt (integer, read-only)
    Timestamp when the product was activated.

.description (string)
    Friendly description of this resource.

.categories (array of string)
    An array of product categories as strings.

.photos (array of string)
    An array of product photo URLs as strings.

.url (string)
    The URL linking to the product information.

.identifiers (object)
    Various identifiers (EPC, ISBN, etc.) as a JSON object with 
    one or more key-value pairs.

.properties (object)
    A JSON object with key-value pairs describing properties of 
    the product.

.tags (array of string)
    Array of string tags associated with this resource.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.

.fn (string)
    Friendly name of the product.

.brand (string)
    The product's brand name.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object representing a platform product.",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name of this resource."
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "activatedAt": {
      "type": "integer",
      "description": "Timestamp when the product was activated.",
      "readOnly": true
    },
    "description": {
      "type": "string",
      "description": "Friendly description of this resource."
    },
    "categories": {
      "description": "An array of product categories as strings.",
      "type": "array",
      "items": { "type": "string" }
    },
    "photos": {
      "description": "An array of product photo URLs as strings.",
      "type": "array",
      "items": { "type": "string" }
    },
    "url": {
      "type": "string",
      "description": "The URL linking to the product information."
    },
    "identifiers": {
      "type": "object",
      "description": "Various identifiers (EPC, ISBN, etc.) as a JSON object with one or more key-value pairs."
    },
    "properties": {
      "type": "object",
      "description": "A JSON object with key-value pairs describing properties of the product."
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "fn": {
      "type": "string",
      "description": "Friendly name of the product."
    },
    "brand": {
      "type": "string",
      "description": "The product's brand name."
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "name", "identifiers.<key>", "tags" ]
}
{
  "id": "UHR8MGsSCct4t9wwRgEKqrUr",
  "createdAt": 1510918625202,
  "customFields": {
    "region": "en_gb"
  },
  "tags": [
    "example",
    "product"
  ],
  "updatedAt": 1510918625202,
  "brand": "ACME",
  "categories": [
    "packaged",
    "consumer"
  ],
  "properties": {
    "in_use": false
  },
  "description": "An example product resource",
  "fn": "Example Product",
  "name": "Example Product",
  "photos": [
    "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg"
  ],
  "url": "https://google.com",
  "identifiers": {
    "ean_13": "438348983329"
  }
}

See also: ScopesDocument


Create a Product

POST /products
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ProductDocument
evrythng products create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/products' \
  -d '{
    "name": "KDL-46EX",
    "description": "Just a simple SONY TV",
    "photos": ["https://images.icecat.biz/img/norm/high/3965331-6265.jpg"],
    "url": "https://icecat.ch/p/sony/kdl-46ex402aep/lcd-tvs-kdl-46ex-3965331.html",
    "identifiers": {
      "UPC": "027242784925"
    },
    "customFields": {
      "FullHD": "true"
    },
  }'
const product = {
  name: 'KDL-46EX',
  description: 'Just a simple SONY TV',
  photos: [ 'https://images.icecat.biz/img/norm/high/3965331-6265.jpg' ],
  url: 'https://icecat.ch/p/sony/kdl-46ex402aep/lcd-tvs-kdl-46ex-3965331.html',
  identifiers: {
    UPC: '027242784925'
  },
  customFields: {
    FullHD: 'true'
  }
};

operator.product().create(product).then(console.log);
Product product = new Product();
product.setName("KDL-46EX");
product.setDescription("Just a simple SONY TV");
apiManager.productService().productCreator(product).execute();
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/products/UGeTG9HmVDPwtKwwwEW7ffWg

{
  "id": "UGeTG9HmVDPwtKwwwEW7ffWg",
  "createdAt": 1346856870595,
  "updatedAt": 1346856870595,
  "name": "CDL-4dsX",
  "description": "Just a simple TV",
  "photos": ["https://images.icecat.biz/img/norm/high/3965331-6265.jpg"]
  "url": "https://icecat.ch/p/sony/kdl-46ex402aep/lcd-tvs-kdl-46ex-3965331.html",
  "customFields": {
    "FullHD": "true"
  },
  "identifiers": {
    "UPC": "027242784925"
  }
}

Read a Product

When provided a productId, the Platform will return a single product document corresponding to that ID, if it exists.

GET /products/:productId
Authorization: $OPERATOR_API_KEY
evrythng products $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/products/UEqs3aV3NyYGVRxhmnphVGdh'
const productId = 'UEqs3aV3NyYGVRxhmnphVGdh';

app.product(productId).read().then(console.log);
String productId = "UEqs3aV3NyYGVRxhmnphVGdh";

Product product = apiManager.productService().productReader(productId).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UEqs3aV3NyYGVRxhmnphVGdh",
  "createdAt": 1473155145323,
  "customFields": {},
  "updatedAt": 1494836869302,
  "brand": "Own",
  "properties": {},
  "description": "Test updated description",
  "fn": "Test Product",
  "name": "Test Product",
  "url": "https://google.com",
  "identifiers": {}
}

Read all Products

Read all products in scope of the authenticating API key. The result may be paginated if there are more than 30 items.

GET /products
Authorization: $OPERATOR_API_KEY
evrythng products list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/products'
// List products in the App's Project context
app.product().read().then(console.log);

// List products managed/visible to the user
user.product.read().then(console.log);
Iterator<PVector<Product>> products = apiManager.productService().iterator().perPage(10).execute();

while(products.hasNext()) {
    PVector<Product> page = products.next();
    for(Product product : page) {
        System.out.println("Product: " + product.getName());
    }
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "UGTdRHP4BDsa95waRhqfYhTh",
    "createdAt": 1495468778553,
    "customFields": {},
    "updatedAt": 1496138109642,
    "properties": {},
    "description": "Use me!",
    "fn": "EngagementProduct",
    "name": "EngagementProduct",
    "identifiers": {}
  }
]

Update a Product

Update a single product by ID.

PUT /products/:productId
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ProductDocument (subset)
evrythng products $id update $payload
curl -i -H "Content-type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/products/UXGmadd2EwqQkXe3F5Gg4hbg' \
  -d '{ 
  	"name": "New Product Name",
    "description": "Updated product description"
  }'
const productId = 'UXGmadd2EwqQkXe3F5Gg4hbg';

user.product(productId).read().then((product) => {
  // Edit properties by property name
  product.name = 'New Product Name';
  product.description = 'New product description';
  
  // Then send the update and print returned updated product
  product.update().then(console.log);

  // Or send all changed properties in one go without printing response
  const update = {
    name: 'New Product Name',
    description: 'Updated product description'
  };
  product.update(update).then(console.log);
});
String productId = "UXGmadd2EwqQkXe3F5Gg4hbg";

Product product = apiManager.productService().productReader(productId).execute();
product.setName("New Product Name");
product.setDescription("Updated product description");
apiManager.productService().productUpdater(productId, product).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UXGmadd2EwqQkXe3F5Gg4hbg",
  "createdAt": 1452868408882,
  "customFields": {},
  "tags": [
    "level", "product", "audio", "tool"
  ],
  "updatedAt": 1453468149305,
  "description": "Updated product description",
  "fn": "Headphones",
  "name": "New Product Name",
  "photos": ["https://www.plantronics.com/images/catalog/product/large/audio995.png"],
  "url": "https://headphones.com",
  "identifiers": {}
}

Delete a Product

Danger!

Deleting a product resource will remove its product reference from all Thngs that point to it. This action cannot be reversed!

DELETE /products/:productId
Authorization: $OPERATOR_API_KEY
evrythng products $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/products/UEqs3aV3NyYGVRxhmnphVGdh'
const productId = 'UEqs3aV3NyYGVRxhmnphVGdh';

operator.product(productId).delete().then(() => console.log('Deleted!'));

// or on the resource itself
operator.product(productId).read((product) => product.delete());
String productId = "UEqs3aV3NyYGVRxhmnphVGdh";

apiManager.productService().productDeleter(productId).execute();
HTTP/1.1 200 OK

Update Multiple Products

Using a suitable filter, it is possible to apply (PUT) an updated ProductDocument to multiple products, providing they match the filter query parameter. For example, all products that begin with "Smart" to contain the 'smart' tag.

PUT /products?filter=name%3DSmart*
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

{
  "tags": [ "smart" ]
}
curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/products?filter=name%3DSmart*' \
  -d '{
    "tags": [ "smart" ]
  }'
const update = { 
  tags: [ "updated" ]
};

operator.product().update(update, { 
  params: { 
    filter: 'name=Test*' 
  } 
}).then(console.log);

The update will be applied asynchronously, and the response will be 204 'No Content'.

HTTP/1.1 204 No Content

Create a Product's Redirection

POST /products/:productId/redirector
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

RedirectionDocument
evrythng products $id redirection create $payload
curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk/redirector' \
  -d '{
    "defaultRedirectUrl": "https://google.com/{productId}"
  }'
const operatorApiKey = '$OPERATOR_API_KEY';
const productId = 'Uk6qwgSReXPat5awagfNpHsk';

EVT.api({
  url: `/products/${productId}/redirector`,
  method: 'POST',
  authorization: operatorApiKey,
  data: { 
    defaultRedirectUrl: 'https://example.com/{productId}'
  }
}).then(console.log);
HTTP/1.1 201 Created
Content-Type: application/json

{
  "createdAt": 1496668317836,
  "updatedAt": 1496668348257,
  "defaultRedirectUrl": "https://google.com/Uk6qwgSReXPat5awagfNpHsk",
  "evrythngUrl": "https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk",
  "shortDomain": "tn.gg",
  "shortId": "799yeEi4qp",
  "hits": 0
}

Read a Product's Redirection

GET /products/:productId/redirector
Authorization: $OPERATOR_API_KEY
evrythng products $id redirection read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk/redirector'
const operatorApiKey = '$OPERATOR_API_KEY';
const productId = 'Uk6qwgSReXPat5awagfNpHsk';

EVT.api({
  url: `/products/${productId}/redirector`,
  authorization: operatorApiKey
}).then(console.log);
HTTP/1.1 200 OK
Content-Type: application/json

{
  "createdAt": 1496664729327,
  "updatedAt": 1496664729327,
  "defaultRedirectUrl": "https://google.com",
  "evrythngUrl": "https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk",
  "shortDomain": "tn.gg",
  "shortId": "39aZNy4g",
  "hits": 0
}

Update a Product's Redirection

PUT /products/:productId/redirector
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

RedirectionDocument
evrythng products $id redirection update $payload
curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk/redirector' \
  -d '{
    "defaultRedirectUrl": "https://google.com/{productId}"
  }'
const operatorApiKey = '$OPERATOR_API_KEY';
const productId = 'Uk6qwgSReXPat5awagfNpHsk';

EVT.api({
  url: `/products/${productId}/redirector`,
  method: 'PUT',
  authorization: operatorApiKey,
  data: { 
    defaultRedirectUrl: 'https://example.com/{productId}'
  }
}).then(console.log);
HTTP/1.1 201 Created
Content-Type: application/json

{
  "createdAt": 1496668317836,
  "updatedAt": 1496668348257,
  "defaultRedirectUrl": "https://google.com/Uk6qwgSReXPat5awagfNpHsk",
  "evrythngUrl": "https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk",
  "shortDomain": "tn.gg",
  "shortId": "799yeEi4qp",
  "hits": 0
}

Delete a Product's Redirection

DELETE /products/:productId/redirector
Content-Type: application/json
Authorization: $OPERATOR_API_KEY
evrythng products $id redirection delete
curl -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/products/Uk6qwgSReXPat5awagfNpHsk/redirector' 
const operatorApiKey = '$OPERATOR_API_KEY';
const productId = 'Uk6qwgSReXPat5awagfNpHsk';

EVT.api({
  url: `/products/${productId}/redirector`,
  authorization: operatorApiKey,
  method: 'DELETE'
}).then(() => console.log('Deleted!'));
HTTP/1.1 200 OK
Content-Type: application/json
 

Every account may contain one or more projects. A project is a container for applications and Application Users, and provides an easy way to share and work with a subset of the resources that exist in an account through Scoping.

Projects are their own scope; every resource may or may not be part of the project scope, which in turn limits visibility of those items to only that project. For more details about scoping, see Scoping.


API Status
Stable:
/projects
/projects/:projectId


ProjectDocument Data Model

.name (string)
    Friendly name of this resource.

.id (string, read-only)
    The ID of this resource.

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.tags (array of string)
    Array of string tags associated with this resource.

.description (string)
    Friendly description of this resource.

.startsAt (integer)
    Timestamp when this project starts.

.endsAt (integer)
    Timestamp when this project ends.

.imageUrl (string)
    URL link to the image to use in the project properties view.

.customFields (object)
    Object of case-sensititve key-value pairs of custom fields 
    associated with the resource.

.identifiers (object)
    Various identifiers (EPC, ISBN, etc.) as a JSON object with 
    one or more key-value pairs.

.shortDomains (array of string)
    An array of short domains assigned for the project, for 
    example: `tn.gg` by default.

.scopes (ScopesDocument)
{
  "type": "object",
  "description": "An object describing a platform project.",
  "properties": {
    "name": {
      "type": "string",
      "description": "Friendly name of this resource."
    },
    "id": {
      "type": "string",
      "description": "The ID of this resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "tags": {
      "type": "array",
      "description": "Array of string tags associated with this resource.",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "description": {
      "type": "string",
      "description": "Friendly description of this resource."
    },
    "startsAt": {
      "type": "integer",
      "description": "Timestamp when this project starts."
    },
    "endsAt": {
      "type": "integer",
      "description": "Timestamp when this project ends."
    },
    "imageUrl": {
      "type": "string",
      "description": "URL link to the image to use in the project properties view."
    },
    "customFields": {
      "type": "object",
      "description": "Object of case-sensititve key-value pairs of custom fields associated with the resource."
    },
    "identifiers": {
      "type": "object",
      "description": "Various identifiers (EPC, ISBN, etc.) as a JSON object with one or more key-value pairs."
    },
    "shortDomains": {
      "type": "array",
      "description": "An array of short domains assigned for the project, for example: `tn.gg` by default.",
      "items": { "type": "string" }
    },
    "scopes": { "$ref": "ScopesDocument" }
  },
  "x-filterable-fields": [ "identifiers.<key>", "name", "tags" ]
}
{
  "id": "U4aPM5gyBg8w9pwaaYKCepVg",
  "createdAt": 1510919010607,
  "customFields": {
    "international": true
  },
  "tags": [
    "example",
    "project"
  ],
  "updatedAt": 1510919010607,
  "name": "Example Project",
  "description": "An example project resource",
  "imageUrl": "https://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg",
  "startsAt": 1510918931000,
  "endsAt": 1542454931000,
  "shortDomains": [
    "tn.gg"
  ],
  "identifiers": {
    "ean_13": "43884389392"
  }
}

See also: ScopesDocument


Create a Project

Create a new project within an account.

POST /projects
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ProjectDocument
evrythng projects create $payload
curl -i -H "Content-type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://api.evrythng.com/projects' \
  -d '{ 
    "name": "My Project" 
  }'
const project = {
  name: 'My Project'
};

operator.project().create(project).then(console.log);
Project project = new Project();
project.setName("My Project");
apiManager.projectService().projectCreator(project).execute();
HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.evrythng.com/projects/UGeTG9HmVDPwtKwwwEW7ffWg

{
  "id": "UGeTG9HmVDPwtKwwwEW7ffWg",
  "createdAt": 1418814288042,
  "updatedAt": 1418814288042,
  "name": "My Project",
  "shortDomains": [ 
     "tn.gg" 
  ]
}

Read a Project

Gets a single project by its projectId.

GET /projects/:projectId
Authorization: $OPERATOR_API_KEY
evrythng projects $id read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/projects/UmxHK6K8BXsa9KawRh4bTbqc'
const projectId = 'UmxHK6K8BXsa9KawRh4bTbqc';

operator.project(projectId).read().then(console.log);
String projectId = "UmxHK6K8BXsa9KawRh4bTbqc";

Project project = apiManager.projectService().projectReader(projectId).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UmxHK6K8BXsa9KawRh4bTbqc",
  "createdAt": 1418814288042,
  "updatedAt": 1418814288042,
  "name": "My Project",
  "shortDomains": [ "tn.gg" ]
}

Read all Projects

Read all projects in an account. The result may be paginated if there are more than 30 items.

GET /projects
Authorization: $OPERATOR_API_KEY
evrythng projects list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/projects'
operator.project().read().then(console.log);
List<Project> projects = apiManager.projectService().projectsReader().list().getResult();
for(Project project : projects) {
    System.out.println(project.toString());
}
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "URG5FDahhBePgNfHVkHTkama",
    "createdAt": 1418814288042,
    "updatedAt": 1418814288042,
    "name": "My Project",
    "shortDomains": [ 
      "tn.gg" 
    ]
  }
]

Update a Project

Update the fields of a project by its id by POSTing a subset of the ProjectDocument containing the changed fields.

PUT /projects/:projectId
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

ProjectDocument (subset)
evrythng projects $id update $payload
curl -i -H "Content-type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/projects/UEqs3aV3NyYGVRxhmnphVGdh' \
  -d '{ 
    "name": "Updated Name" 
  }'
const projectId = 'UEqs3aV3NyYGVRxhmnphVGdh';

const update = {
  name: 'Updated Name'
};

operator.project(projectId).update(update).then(console.log);
String projectId = "UEqs3aV3NyYGVRxhmnphVGdh";

Project project = apiManager.projectService().projectReader(projectId).execute();
project.setName("Updated Name");

apiManager.projectService().projectUpdater(projectId, project).execute();
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "UEqs3aV3NyYGVRxhmnphVGdh",
  "createdAt": 1418814288042,
  "updatedAt": 1418814288042,
  "name": "Updated Name",
  "shortDomains": [ "tn.gg" ]
}

Delete a Project

Delete a project by its id. This will also remove access to any contained applications, Application Users, etc.

Danger

This action cannot be reversed! You will lose access to ALL applications and Application Users within the deleted project.

DELETE /projects/:projectId
Authorization: $OPERATOR_API_KEY
evrythng projects $id delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/projects/UEqs3aV3NyYGVRxhmnphVGdh'
const projectId = 'UEqs3aV3NyYGVRxhmnphVGdh';

operator.project(projectId).delete().then(() => console.log('Project deleted'));
String projectId = "UEqs3aV3NyYGVRxhmnphVGdh";

apiManager.projectService().projectDeleter(projectId).execute();
HTTP/1.1 200 OK
Suggest Edits

Properties

 

Thngs and products can have many properties, which are simple typed key/value pairs of data that are attached to a resource. Where it gets interesting is that each property update is timestamped and stored historically, which allows you to retrieve the set of all the values of a property during any specific time range and infer trends over time.

The most common use case of properties is to store dynamic information about a Thng, which is likely to change over time. This is particularly useful for devices, where properties can store the sensor readings of the device. For longer-lived data that does not require a history, customFields or identifiers should be used as appropriate.

For example, the current power consumption of a bulb should be stored in properties, the particular IP address is has connected to a customField, and the model number or SKU code in identifiers.


API Status
Stable:
/thngs/:thngId/properties
/products/:productId/properties


PropertyDocument Data Model

Thng or product properties take the form of an array of PropertyDocument objects that always contain a key (case-insensitive, gets converted to lowercase automatically by the API), a value, and a timestamp.

.key (string)
    The property key-value key.

.value (string,integer,boolean)
    The property key-value value.

.timestamp (integer, read-only)
    The timestamp of the property update.

.createdAt (integer, read-only)
    Timestamp when the resource was created.
{
  "type": "object",
  "description": "An object representing a single property update. The `value` property may be a string or integer.",
  "properties": {
    "key": {
      "type": "string",
      "description": "The property key-value key."
    },
    "value": {
      "type": [ "string", "integer", "boolean" ],
      "description": "The property key-value value."
    },
    "timestamp": {
      "type": "integer",
      "description": "The timestamp of the property update.",
      "readOnly": true,
      "minimum": 0
    },
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    }
  },
  "x-filterable-fields": [ "timestamp" ]
}
{
  "createdAt": 1507734727579,
  "timestamp": 1507734727579,
  "key": "example_property",
  "value": 10
}

Property Units

If the property type is a number, then you can visualize it as a graph in the dashboard. For this reason, we suggest you don't include the unit in value, but rather encode it in the property name. For example:

{
  "key": "temperature_celsius",
  "value": 21
}

If the optional timestamp is not provided when updating the property, it is automatically set by the API at the moment when the request has been processed.

If a device is not connected permanently (e.g. due to limited network availability or power saving), it can cache the sensor readings and upload them in batches by specifying timestamps to accompany each object.


Create/Update Properties

Create

When a resource is created, you can specify an initial set of properties and their values with a POST request.

POST /thngs/:thngId/properties
POST /products/:productId/properties

Update

To update those properties or to add new ones to the resource, use PUT on the following endpoints, with an array of PropertyDocument JSON object containing the changed fields.

PUT /thngs/:thngId/properties
PUT /products/:productId/properties

If the properties being updated do not exist, they are created automatically by this request and no error/notification will be returned.

Note

Exceptionally, to cope with the limitations of mobile network providers you can use both POST and PUT to create/update multiple properties, which behave identically in this particular case.

However, only the PUT method may be used to update properties by name.

The returned payload is an array of the properties updated, not all of the Thng's the properties.

PUT /thngs/:thngId/properties
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

[ PropertyDocument, ... ]
evrythng thngs $id properties create $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/thngs/UEqs3aV3NyYGVRxhmnphVGdh/properties' \
  -d '[{
    "key": "temperature_celsius",
    "value": 33
  }, {
    "key": "humidity_percent",
    "value": 71
  }]'
const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';

const newProperties = [{
  key: 'temperature_celsius',
  value: 33
}, {
  key: 'humidity_percent',
  value: 71
}];

// in a single request
user.thng(thngId).property().update(newProperties).then(console.log);

// or on the resource itself
user.thng(thngId).read().then((thng) => {
  thng.property().update(newProperties).then(console.log);
});
String thngId = "UEqs3aV3NyYGVRxhmnphVGdh";

List<Property<?>> properties = new ArrayList<>();
properties.add(new NumberProperty("temperature_celsius", 33));
properties.add(new NumberProperty("humidity_percent", 71));

// Add to Thng
apiManager.thngService().propertiesCreator(thngId, properties).execute();

// Add to product
apiManager.productService().propertiesCreator(productId, properties).execute();
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "timestamp": 1346860078782,
    "createdAt": 1346860078782,
    "key": "temperature_celsius",
    "value": 33
  },
  {
    "timestamp": 1346860078782,
    "createdAt": 1346860078782,
    "key": "humidity_percent",
    "value": 71
  }
]

Read All Properties

GET /thngs/:thngId/properties
GET /products/:productId/properties

Retrieve a list of all the properties of a Thng or product by its ID. The result may be paginated if there are more than 30 items.

GET /thngs/:thngId/properties
Authorization: $OPERATOR_API_KEY
evrythng thngs $id properties list
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/thngs/UEqs3aV3NyYGVRxhmnphVGdh/properties'
const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';

// in a single request
user.thng(thngId).property().read().then(console.log);

// or on the resource itself
user.thng(thngId).read().then((thng) => {
  thng.property().read().then(console.log);
});
// thng from previous thngService reader invocation
Map<String, Object> properties = thng.getProperties();
for(Map.Entry<String, Object> entry : properties.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue().toString();
    System.out.println("key=" + key + " value=" + value);
}

The returned payload is the complete array of all the properties with the last value of each.

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "key": "temperature_celsius",
    "value": 33,
    "timestamp": 1346856615704,
    "createdAt": 1346856615704
  }, 
  {
    "key": "humidity_percent",
    "value": 71,
    "timestamp": 1346856615704,
    "createdAt": 1346856615704
  }, 
  {
    "key": "light_sensor_cd",
    "value": 249,
    "timestamp": 1346856615704,
    "createdAt": 1346856615704
  }
]

Create/Update a Single Property

Properties can be updated individually using their dedicated endpoints. If the property does not exist, it will be created automatically by this request and no error/notification will be returned.

PUT /thngs/:thngId/properties/:key
PUT /products/:productId/properties/:key

It's also possible to upload cached values of a property in batches by specifying timestamps for each data item object.

PUT /thngs/:thngId/properties/:key
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

PropertyDocument
evrythng thngs $id properties $key update $payload
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://api.evrythng.com/thngs/UEqs3aV3NyYGVRxhmnphVGdh/properties/my_key' \
  -d '[{
    "value": 301
  }]'
const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';
const key = 'temperature_celsius';
const value = 23;

// in a single request
user.thng(thngId).property(key).update(value).then(console.log);

// or on the resource itself
user.thng(thngId).read().then((thng) => {
  thng.property(key).update(value).then(console.log);
});
String value = "UEqs3aV3NyYGVRxhmnphVGdh";
String key = "temperature_celsius";
String value = "23";

apiManager.thngService().propertyUpdater(thngId, key, value).execute();
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "timestamp": 1347549410295,
    "createdAt": 1347549410295,
    "value": 301
  }
]

You can also provide data via three different payload types to the property() update method:

const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';
const key = 'temperature_celsius';

// 1. Just the value (simple values only - string, number, boolean. 
// Use 2. for arrays and objects)
user.thng(thngId).property(key).update(320);

// 2. An object (similar to the API), allowing you to specify the timestamp:
user.thng(thngId).property(key).update({
  value: 320,
  timestamp: 142963528000
});

// 3. In bulk, with multiple objects
const updates = [{
  value: 320,
  timestamp: 142963528000
}, {
  value: 420,
  timestamp: 142963535600
}];
user.thng(thngId).property(key).update(updates);

Read a Property's History

To retrieve the history of values of a specific property, you must access the unique endpoint for each property. By default, all the updates of this property are returned using pagination in a reverse history fashion (the first element of the returned array is the latest update).

GET /thngs/:thngId/properties/:key
GET /products/:productId/properties/:key

If you attempt to fetch the history of values for a property that doesn't exist you will receive an HTTP 200 status code and an empty list as a result.

GET /thngs/:thngId/properties/:key[?from=Timestamp&to=Timestamp]
Authorization: $OPERATOR_API_KEY
evrythng thngs $id properties $key read
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://api.evrythng.com/thngs/UEqs3aV3NyYGVRxhmnphVGdh/properties/temperature_celsius'
const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';
const key = 'temperature_celsius';

// in a single request
user.thng(thngId).property(key).read().then(console.log);

// or on the resource itself
user.thng(thngId).read().then((thng) => {
  thng.property(key).read().then(console.log);
});
String key = "temperature_celsius";

// thng from previous thngService reader invocation
Map<String, Object> properties = thng.getProperties();
String value = properties.get(key).toString();

For accessing only a subset of all the updates to a single property, you can specify a time range using ?from=Timestamp and ?to=Timestamp to specify respectively the beginning and end of the time window. You will receive an array of all the property updates during this time.

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "timestamp":1346860078782,
    "createdAt":1346860078782,
    "value":33
  },
  {
    "timestamp":1346856870595,
    "createdAt":1346856870595,
    "value":29
  },
  {
    "timestamp":1346856779570,
    "createdAt":1346856779570,
    "value":32
  }
]

Delete a Property

Property updates are not uniquely identified (do not have their own URL). Therefore, the only way to delete data points is to append the ?to=Timestamp URL query parameter to specify a point in time before which all the data points will be removed.

DELETE /thngs/:thngId/properties/:key
DELETE /products/:productId/properties/:key

Warning

If the ?to= parameter is not specified, ALL updates of this property will be deleted!

DELETE /thngs/:thngId/properties/:key[?to=Timestamp]
Authorization: $OPERATOR_API_KEY
# Deletes entire property history
evrythng thngs $id properties $key delete
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/thngs/UEqs3aV3NyYGVRxhmnphVGdh/properties/my_key'
const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';
const key = 'temperature_celsius';

// in a single request
operator.thng(thngId).property(key).delete();

// or on the resource itself
operator.thng(thngId).read().then((thng) => thng.property(key).delete());
String thngId = "UEqs3aV3NyYGVRxhmnphVGdh";
String key = "temperature_celsius";

apiManager.thngService().propertyDeleter(thngId, key).execute();
HTTP/1.1 200 OK

Delete all Properties

Delete all the properties of a Thng or product. Example below is for Thngs.

DELETE /thngs/:thngId/properties
Authorization: $OPERATOR_API_KEY
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://api.evrythng.com/thngs/UEqs3aV3NyYGVRxhmnphVGdh/properties'
const thngId = 'UEqs3aV3NyYGVRxhmnphVGdh';

operator.thng(thngId).property().delete();
HTTP/1.1 200 OK

System Properties

In addition, the EVRYTHNG Platform automatically sets some system properties. They start with ~ (tilde) and are read-only. Apart from that they behave exactly like other properties.

The following lists the currently available system properties available on Thngs:

  • ~connected - Boolean
    Set to true if the Thng is updated with its own API key and if it is currently connected to the pub/sub broker through MQTT or WebSockets. The property is created on the Thng first connection and updated every time the Thng disconnects or connects again.
Suggest Edits

Redirections

 

Redirections allow fixed physical barcodes and QR codes to point to dynamically changing locations. Each redirection resource therefore contains the ID of the Thng or product it is associated with, the short domain and short URL it may encode, and the full URL it will redirect to.

Redirector

Using the Redirector service, rules including location, user data, action context, date/time, and more can be used to selectively redirect the user, enabling a more powerful experience. For example, a different web page to be returned for users in different countries, or during different days of the week.

See Resource Redirections for more conceptual information.


API Status
Stable: https://tn.gg/redirections


RedirectionDocument Data Model

.createdAt (integer, read-only)
    Timestamp when the resource was created.

.updatedAt (integer, read-only)
    Timestamp when the resource was updated.

.defaultRedirectUrl (string)
    The location to redirect to.

.redirectUrl (string)
    The redirect URL.

.evrythngUrl (string, read-only)
    The location of the EVRYTHNG resource.

.evrythngId (string, read-only)
    The EVRYTHNG ID of the associated resource.

.shortDomain (string, read-only)
    The associated short domain for the redirection.

.shortId (string, read-only)
    The short ID of the redirection

.type (string, read-only, one of 'thng', 'product', 'collection', 'place')
    The type of the associated EVRYTHNG resource.

.hits (integer, read-only)
    The number of times the redirection has been hit.
{
  "type": "object",
  "description": "A redirection on a resource.",
  "properties": {
    "createdAt": {
      "type": "integer",
      "description": "Timestamp when the resource was created.",
      "readOnly": true,
      "minimum": 0
    },
    "updatedAt": {
      "type": "integer",
      "description": "Timestamp when the resource was updated.",
      "readOnly": true,
      "minimum": 0
    },
    "defaultRedirectUrl": {
      "type": "string",
      "description": "The location to redirect to."
    },
    "redirectUrl": {
      "type": "string",
      "description": "The redirect URL."
    },
    "evrythngUrl": {
      "type": "string",
      "description": "The location of the EVRYTHNG resource.",
      "readOnly": true
    },
    "evrythngId": {
      "type": "string",
      "description": "The EVRYTHNG ID of the associated resource.",
      "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
      "readOnly": true
    },
    "shortDomain": {
      "type": "string",
      "description": "The associated short domain for the redirection.",
      "readOnly": true
    },
    "shortId": {
      "type": "string",
      "description": "The short ID of the redirection",
      "minLength": 8,
      "maxLength": 10,
      "readOnly": true
    },
    "type": {
      "type": "string",
      "description": "The type of the associated EVRYTHNG resource.",
      "enum": [ "thng", "product", "collection", "place" ],
      "readOnly": true
    },
    "hits": {
      "type": "integer",
      "description": "The number of times the redirection has been hit.",
      "readOnly": true
    }
  }
}
{
  "createdAt": 1510919459418,
  "defaultRedirectUrl": "https://google.com?thng=UFqMRDbaqm8EEMRaRF5h7cEg",
  "evrythngId": "UFqMRDbaqm8EEMRaRF5h7cEg",
  "evrythngUrl": "https://api.evrythng.com/thngs/UFqMRDbaqm8EEMRaRF5h7cEg",
  "hits": 4,
  "redirectUrl": "https://google.com?thng=UFqMRDbaqm8EEMRaRF5h7cEg",
  "shortDomain": "tn.gg",
  "shortId": "GrqPQbvgkG",
  "type": "thng",
  "updatedAt": 1510919527219
}

Create a Redirection

Thng and Product Redirections

It is possible to create a Thng or products' redirection directly on its resource. Read the Thngs and Products pages for more information.

To create a redirection for a EVRYTHNG resource it is required to specify resource type and reference evrythngId. The required parameter defaultRedirectUrl is the target URL of the application that will be called for each access of the short URL.

Note

The default response is a QR code image representing the redirection, unless the accept request header is set to application/json.

POST https://tn.gg/redirections
Content-Type: application/json
Authorization: $OPERATOR_API_KEY

RedirectionDocument
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X POST 'https://tn.gg/redirections' \
  -d '{
    "defaultRedirectUrl":"https://museum.com/displayWorks/catalogue.php?catalogue_id={evrythngId}",
    "evrythngId":"UVpfh4EFsBpasUmnVDWdktKs",
    "type":"thng"
  }'
const operatorApiKey = '$OPERATOR_API_KEY';
const thngId = 'UH4nVsWVMG8EEqRawkMnybMh';
const defaultRedirectUrl = 'https://example.com?thng={thngId}';

evrythng.api({
  apiUrl: 'https://tn.gg',
  url: '/redirections',
  method: 'post',
  authorization: operatorApiKey,
  headers: { Accept: 'application/json' },
  data: {
    evrythngId: thngId,
    defaultRedirectUrl,
    type: 'thng',
  },
}).then(console.log);