Some resource types include the concept 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, or their current/last known position. For example, if a pallet is being tracked through a supply chain, its location could be updated each time it is scanned by a transport company member at each stop along the way, creating a picture of its unique journey useful to both the brand and the consumer.

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. Accuracy of a guessed location will vary depending on the apparent IP and location of the request seen by the EVRYTHNG API.

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, then latitude coordinates.

🚧

Coordinate Order

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


API Status
General Availability:
/thngs/:thngId/location


LocationDocument Data Model

.position (GeoJSONPointDocument)
    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)
    Project and user scopes arrays.
{
  "additionalProperties": false,
  "type": "object",
  "description": "An object representing a location. Either 'position' or 'place' us required.",
  "properties": {
    "position": {
      "type": "object",
      "description": "A GeoJSON Point object. The coordinate order is longitude, then latitude.",
      "required": ["type", "coordinates"],
      "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": {
      "additionalProperties": false,
      "type": "object",
      "description": "Project and user scopes arrays.",
      "required": ["users", "projects"],
      "properties": {
        "users": {
          "type": "array",
          "description": "An array of Application User IDs this resource is scoped to.",
          "items": { "type": "string" }
        },
        "projects": {
          "type": "array",
          "description": "An array of project IDs this resource is scoped to.",
          "items": {
            "type": "string",
            "description": "The ID of this resource.",
            "pattern": "^[abcdefghkmnpqrstwxyABCDEFGHKMNPQRSTUVWXY0123456789]{24}$",
            "readOnly": true
          }
        }
      }
    }
  },
  "x-filterable-fields": ["timestamp"]
}
{
  "latitude": -37,
  "longitude": -179.3,
  "position": {
    "type": "Point",
    "coordinates": [
      -179.3,
      -37
    ]
  }
}

See also: ScopesDocument

Filterable Fields

This resource type can be filtered using the following fields and operators.

FieldTypeOperators
timestampNumber<, >

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
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X GET 'https://$EVT_API_DOMAIN/thngs/U2a4AsGtqerbcWD6qhYGfb5d/location'
const thngId = 'U2a4AsGtqerbcWD6qhYGfb5d';

user.thng(thngId).locations()
  .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 GPS tracker on a shipping container that updates the whole set of locations it has been through once per hour, or when it is in range of a network instead of sending each GPS sensor reading individually.

Note: 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, ... ]
curl -i -H "Content-Type: application/json" \
  -H "Authorization: $OPERATOR_API_KEY" \
  -X PUT 'https://$EVT_API_DOMAIN/thngs/U2wm8b42MVNxTCX6MYDrRpyd/location' \
  -d '[{
      "position": {
        "type": "Point",
        "coordinates": [ -17.3, 36 ]
      }
    }, {
      "timestamp": 1347028945711,
      "position": {
        "type": "Point",
        "coordinates": [ -179.3, -37 ]
      }
    }]'
const thngId = 'U2wm8b42MVNxTCX6MYDrRpyd';

// Two recent location samples
const payload = [{
  position: {
    type: 'Point',
    coordinates: [-17.3, 36],
  },
}, {
  timestamp: 1347028945711,
  position: {
    type: 'Point',
    coordinates: [-179.3, -37],
  },
}];

user.thng(thngId).locations()
  .update(payload)
  .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
curl -H "Authorization: $OPERATOR_API_KEY" \
  -X DELETE 'https://$EVT_API_DOMAIN/thngs/U2wm8b42MVNxTCX6MYDrRpyd/location'
const thngId = 'U2wm8b42MVNxTCX6MYDrRpyd';

operator.thng(thngId).locations()
  .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. If you are supplying the coordinates, make sure to also specify locationSource as sensor, or geoIP will be used instead.

An example is shown below:

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