Navbar
cURL NodeJS Python Java PHP Ruby Swift ObjC

Guides

APIs

This guide provides an overview of APIs for the following HyperTrack features:

About

HyperTrack APIs allow to review and control devices and trips using an HTTP-based RESTful interface with JSON format. HyperTrack APIs are mainly used to integrate with the HyperTrack platform through your backend server. It allows you to retrieve data submitted by HyperTrack's mobile SDKs and control Trip tracking, an integral part of the HyperTrack platform. Using the APIs allows you to obtain the full state of all tracked devices and trips.

Features

HyperTrack exposes two different APIs: Devices API & Trips API.

Devices

HTTP 200 - Single device payload

{
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "location": {
    "speed": 4.20,
    "accuracy": 14.09,
    "bearing": 193.12,
    "geometry": {
      "type": "Point",
      "coordinates": [
        35.1016383,
        47.8391314,
        65.40
      ]
    },
    "recorded_at": "2019-07-18T18:01:59.064000Z",
  },
  "device_status": {
    "data": {
      "recorded_at": "2019-07-30T01:38:45.610000Z",
      "activity": "stop"
    },
    "value": "active"
  },
  "views": {
    "share_url":"https://trck.at/abcdef",
    "embed_url":"https://embed.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF?publishable_key=abc"
  },
  "battery": "normal",
  "device_info": {
    "timezone": "America/Los_Angeles",
    "os_name": "iOS",
    "device_brand": "Apple",
    "sdk_version": "3.3.2",
    "device_model": "iPhone X",
    "network_operator": "T-Mobile",
    "name": "Alex’s Phone",
    "os_version": "12.4"
  },
  "registered_at": "2019-07-10T01:38:45.610000Z",
  "metadata": { ... }
}

As soon as one of the HyperTrack mobile SDKs is initialized on a mobile device, it will try to transmit data to the HyperTrack platform. All tracked devices will be available through the Devices API. Each device entity contains the following data:

The Devices API also allows you to remove tracked devices. Removal of a device will not automatically remove trip details collected in the past.

Additionally, the Devices API provides you an ability to update device name and its metadata via an HTTP PATCH.

Trips

HTTP 200 - Completed trip payload

{
  "trip_id": "aabb2233-8899-4455-3210-aabbccddeeff",
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "started_at": "2019-05-03T06:25:51.238000Z",
  "completed_at": "2019-05-03T06:25:51.238000Z",
  "status": "completed",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "metadata": {
    "customer_id": "ABC123"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": "2019-05-03T06:25:51.238000Z",
    "arrived_at": "2019-05-03T06:25:51.238000Z"
  },
  "summary": {
     ...
  }
}

Use Trips when you want to track the movement of the device to an expected destination or set of geofences. Trips include estimates (route/ETA) to destination, geofences, shareable and embeddable views, and summaries of movement and markers.

With the Trips API, developers can create, track, and complete active trips. Every trip entity includes the following data:

It is important to understand that a single device can be associated with multiple active trips. Thus, making it possible to track different activities at the same time. For instance, one trip could track the entire shift of a worker and another one could track a trip from one destination to another.

The Trips API controls the tracking status of a device. With the creation of a trip, the HyperTrack mobile SDK will try to start tracking of the device associated with the trip. When all active trips associated with a device are completed, the SDK will stop tracking.

Use Cases

Developers use Devices API to build:

Developers use Trips API to:

Architecture

The HyperTrack mobile SDKs send a time-series of events from the device to the HyperTrack server. These events are processed and then stored on the HyperTrack platform. Your server can retrieve the data through API requests.

architecture

As opposed to Webhooks, the REST APIs do not notify your server as events come in. The APIs will respond with the most recent data available at the time of the API call. Oftentimes APIs are used to synchronize the state of devices and trips and complemented with webhooks for real time actions or views.

Setup

Usage of HyperTrack APIs requires a HyperTrack account, an initialized SDK tracking a mobile device, and configurations on your server. Please review the following guidelines to ensure you can leverage HyperTrack APIs successfully.

Account creation

To get started with HyperTrack, you first need to sign up. Please follow the steps below to get your account and obtain account details like AccountID or SecretKey. These details are important to start tracking your first device and making API calls.

Sign Up

Please go to this page and complete the signup form.

Indicating an accurate device count, app goal, and development status will help us tailor your experience with HyperTrack.

signup

After clicking on "Accept & Continue", you will be presented with a screen asking you to verify your email.

Account verification

Please check your inbox for an email with the subject line "HyperTrack: Please verify your email address".

The email contains a verification URL. Please open the URL to confirm your email.

Dashboard onboarding

When you visit the dashboard for the first time (and until you track your first device), you will be presented with a welcome screen:

welcome

You can familiarize yourself with the navigation. It includes ...

Account details

For the purpose of the API guide, it is important to obtain the following account details:

These details are all presented on the Setup page of the dashboard. You can find the page by clicking on the burger menu on the top right side.

setup

Equipped with your verified account and keys, you can start tracking your first device.

Device Tracking

The welcome screen on the dashboard allows you to choose a preferred way to start tracking your first device. You have three options to select from:

It’s up to you to select the most appropriate option. Here’s a brief guide to help you make your decision:

Option Main Purpose Time to complete Production readiness
App Install Share device location and trip details with team members Minutes -
Quickstart Track your first device in your own app Minutes - Hours Medium
App Fork Create a new tracking app Hours - Days High

As soon as you completed either one of the options above, your dashboard will show your first tracked device:

first

With tracked devices on the HyperTrack platform and your account keys, you can set up your server to make your first API requests.

Server

HyperTrack REST APIs can be consumed through HTTP requests. Please follow the guidelines below to ensure a working server setup.

HTTPS Methods

Depending on the HyperTrack API and endpoint, your server should support the following HTTPS methods: GET, POST, and DELETE.

HTTP Response Codes

HyperTrack APIs implement appropriate HTTP response codes to indicate how the HTTP request was processed. In success cases, you will receive the expected JSON payload. However, API requests can fail due to client or server errors. We adopted the RFC 7807 standard for our error messages. Please ensure your implementation handles error messages for all HTTP requests.

JSON Payload

The payload you will receive with HTTPS requests is formatted in JSON. You need to implement the capability to parse JSON objects in order to leverage the HTTP response body content.

You should use a JSON parser that handles converting the escaped representation of control characters back to their ASCII character values (for example, converting \n to a newline character).

The HyperTrack APIs make use of GeoJSON and ISO 8601 timestamp formats, which you should handle appropriately as well.

Webhooks

To fully utilize the benefits of the Trips API, you should consider implementing the capability to receive, process, and react to Webhooks sent by HyperTrack. Please review the Webhooks guide for further details.

With tracked devices, account details, and working server setup, it is time to send the first HTTP request to the HyperTrack APIs.

Requests

This chapter provides detailed guidelines to send HTTP requests to the HyperTrack APIs.

Authentication

HTTP 401 - Unauthorized

{
  "message": "Unauthorized"
}

API requests require Basic Authentication to succeed. Failing to set the Authorization header in the right format with correct credentials will result in errors.

A sample Authorization header looks like this:

Authorization: Basic V3AxTGdWTjNZSGFmOHVRcE9qalTNTMm5BaEF1RA==

Generating Basic Auth header

credentials="$(echo -n "{AccountId}:{SecretKey}" | base64)"
header="Authorization: Basic $credentials"
const auth =
  "Basic " + new Buffer("{AccountId}" + ":" + "{SecretKey}").toString("base64");
const header = { Authorization: auth };
base64string = base64.encodestring('%s:%s' % ('{AccountId}', '{SecretKey}')).replace('\n', '')
header = ("Authorization: Basic %s" % base64string)
String authString = "Authorization: Basic " +
                Base64.getEncoder().encodeToString(
                        String.format("%s:%s", "{AccountId}","{SecretKey}")
                                .getBytes()
                );
<?php

$header = "Authorization: Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

?>
$header = 'Authorization: Basic ' + Base64.encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
let base64encoded = "{AccountId}:{AccountId}".data(using: .isoLatin1)?.base64EncodedString() ?? ""
urlRequest.addValue("Basic \(base64encoded)", forHTTPHeaderField: "Authorization")
[request addRequestHeader:@"Authorization"
                    value:[NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", "{AccountId}", "{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]];

The header should be constructed as followed:

With authentication in place, you should be able to make successful HTTP requests to HyperTrack APIs.

Base URL and endoints

All HyperTrack APIs have are available on the same base URL:

https://v3.api.hypertrack.com/

However, each API is reachable on a different endpoint:

Path Parameters

Path parameters are used to accomplish querying, filtering, searching, sorting, and for pagination.

Query Trips API by trip_id

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/trips/{trip_id}",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/trips/{trip_id}", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/{trip_id}")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/{trip_id}');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/{trip_id}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/{trip_id}")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/{trip_id}"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Querying

HyperTrack APIs support querying to request a single resource using the respective identifier:

Filtering

Filter Trips API sample URLs

# reduce result set size to 5 trips
GET https://v3.api.hypertrack.com/trips?limit=5

# find trips with status "completed"
GET https://v3.api.hypertrack.com/trips?status=completed

It is planned to provide filtering capabilities to ...

Pagination

Coming soon: Trips API pagination parameters

# get items 180-200 form entire result set
https://v3.api.hypertrack.com/trips?offset=180&limit=20

The APIs utilize token-based pagination, which will allow to control how many items should be skipped in the returned result set.

The links section of the response provides a next link to request the next page of results.

Sorting and searching

Sorting or searching capabilities are not provided yet. Please cast your vote on our product board if you need this feature.

Postman Collection

We published a Postman Collection to make it easier and faster to experiment with the HyperTrack APIs. Postman Collections lists all available API endpoints, allow making API requests instantly (with Basic Auth), and can generate reusable code snippets to make API requests using the programming language of your choice.

Try it out yourself:

Run in Postman

Responses

The following section describes how to handle the API responses sent by HyperTrack.

Payload and Headers

The responses will always include a set of headers. Please review them carefully when implementing the APIs.

Content-Type

The body payload sent by the server is in application/json, which means that the JSON format is enforced for the payload by default. Please ensure you handle JSON appropriately before processing the data.

JSON arrays and objects

Depending on the result set of the response payload, the server will either respond with an array of a JSON object. For instance, retrieving a single trip/device will provide an object. However, retrieving a set of devices/trips, will provide an array of JSON objects. Please ensure you handle both cases correctly.

Pagination

The payload structure of responses is change as follows.

{
  "data": [
    // trip objects
  ],
  "links": {
    "next": "https://v3.api.hypertrack.com/trips/?pagination_token=abc"
  }
}
Name Type Description
links reference object Object with references to use for pagination
links.next URL URL with pointer to the next page

The links object will include all pagination and filtering properties to navigate through result sets with the same query as initiated. You should use the links properties and prefix them with the API base URL to make consecutive API calls when scrolling through the result set.

The easiest way to identify the end of the pagination is to look for the existence of the links.next property. If it doesn’t exist, you completed the pagination.

Processing States

HTTP 202 - Trip completion processing payload

{
  "message": "pending completion for trip '00112233-4455-6677-8899-AABBCCDDEEFF'"
}

In some scenarios, API requests cannot be fully processed before an API response has to be issued. An example of this is the completion of a trip. The request needs to be processed on the platform and trip completion needs to be confirmed on the mobile SDK of the device. To handle the processing, the API will respond with a processing state (e.g. processing_completion for trips).

To handle the processing state, you should anticipate the response to be in a different format (see the message property).

After processing the request on the HyperTrack platform, a webhook will be sent out and the requested resource will be available through the API. For trip completion, you will receive a completed trip webhook. After the webhook arrival, you can also call the Trips API to retrieve the trip resource using the trip_id.

Errors

HTTP 401 - Trip not found error payload

{
  "status": 404,
  "code": "trip_not_found",
  "title": "Trip could not be found",
  "type": "https://docs.hypertrack.com/#trips-api-trip-not-found",
  "detail": "Trip with the id '00112233-4455-6677-8899-AABBCCDDEEFF' does not exist"
}

We are adopting the RFC 7807 standard for API error messages.

The standard requires at least the type property. Everything else is optional. For HyperTrack, we always send title, detail, status, and code in addition. To detail out some errors (for instance multiple invalid fields), additional properties will be available.

Parameter Type Description
status Number HTTP status code
code String Error class code
title String Brief summary of the error class
type URL URL to the respective error page (about:blank if none is provided)
detail String Detailed description of the error instance
invalid_params Object A list of invalid parameters to review (options)

Please review the reference page to see all possible HTTP errors returned by the HyperTrack APIs.

Usage

Devices

Devices API lets you retrieve the current location and movement status data for tracked devices. Developers use it in applications to ...

Review device status

The device_status object has properties that are conditionally to device_status.value.

Active

Active device status includes an activity

"device_status": {
    "data": {
      "recorded_at": "2019-07-30T01:38:45.610000Z",
      "activity": "stop"
    },
    "value": "active"
  }

The device is actively sending updates. In that case, the device_status.data object is provided with an activity property. It can be one of stop, walk, run, cycle, or drive (see the references for more details).

Inactive

Inactive device status includes a reason

"device_status": {
            "data": {
                "recorded_at": "2019-09-03T16:39:35.326000Z",
                "reason": "stopped_programmatically"
            },
            "value": "inactive"
        }

The device is not trackable for known reasons. In that case, the device_status.data object is provided with a reason property. It can be one of:

Android iOS Description
location_permissions_denied motion_activity_permissions_denied User denied permissions
location_services_disabled motion_activity_services_disabled User disabled services
motion_activity_services_unavailable motion_activity_services_unavailable Activity services not available on device
stopped_programmatically stopped_programmatically Tracking was stopped programmatically from host application

Disconnected

Disconnected device status does not have any data

"device_status": {
            "data": {},
            "value": "disconnected"
        }

Connection with the device was lost unexpectedly (no data received for over an hour). In that case, the device_status.data object is empty.

Monitor battery state

Battery status property

"battery": "normal"

Device objects contain a battery property to indicate the state of the device battery. The property can take one of the following values: low, normal, or charging

Assign name and metadata

Device name and custom metadata

{
  "name": "Alex’s Phone",
  "metadata": {
    "customer_id": "ABC123"
  }
}

HyperTrack views and developer integrations rely on the device names and metadata for filtering, selection, and more. Customizing these device properties makes navigation and identification of workers easier. Developers often add unique identifiers, grouping information, or annotations that are frequently accessed for devices.

Here are some examples:

In order to set a device name and update associated metadata, you may either use SDKs (iOS / Android) or the Devices API.

By default, the property name is set to the name of the device as configured in the device settings. With the SDK, you can set and customize this name. The Devices API allows you to authoritatively set and modify the name for the device.

Map device location

Device location payload

"location": {
    "speed": 4.20,
    "accuracy": 14.09,
    "bearing": 193.12,
    "geometry": {
      "type": "Point",
      "coordinates": [
        35.1016383,
        47.8391314,
        65.40
      ]
    },
    "recorded_at": "2019-07-18T18:01:59.064000Z",
  }

Use the location object to display the location of a device on a map. It is important to understand the GeoJSON format to handle the data correctly:

The accuracy value is often used to draw a "halo effect" around the location dot with the accuracy (in meters) value being the radius of the surrounding ring. In addition, bearing (in degrees starting at due north) is used to draw a directional indicator at the location dot.

location

Share device views

Device views payload includes two URLs

"views": {
    "share_url": "https://trck.at/abcdefg",
    "embed_url": "https://embed.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF?publishable_key={your_key}"
}

The Devices API returns unique and static URLs for every device. The URLs point up single device views that can be shared through messaging or embedded into your own dashboard. Please see the Views guide for more details.

live device view

Trips

Trips API lets you manage, track, and review journeys with destinations or places of interests (geofences) along the way. Developers use it in applications to ...

Get routes and ETAs

Run in PostmanPOST https://v3.api.hypertrack.com/trips/

payload='{
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    }
  }
}'

curl -X POST \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/ \
  -H 'Content-Type: application/json' \
  -d $payload
const request = require("request");

const payload = {
  device_id: "00112233-4455-6677-8899-AABBCCDDEEFF",
  destination: {
    geometry: {
      type: "Point",
      coordinates: [-122.3980960195712, 37.7930386903944]
    }
  }
};

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/trips/",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  },
  body: payload
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests
import json

payload = {
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    }
  }
}

response = requests.request("POST", "https://v3.api.hypertrack.com/trips/", data=json.dumps(payload).encode("utf-8"), auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType,"{\n" +
        "  \"device_id\": \"00112233-4455-6677-8899-AABBCCDDEEFF\",\n" +
        "  \"destination\": {\n" +
        "    \"geometry\": {\n" +
        "      \"type\": \"Point\",\n" +
        "      \"coordinates\": [-122.3980960195712, 37.7930386903944]\n" +
        "    }\n" +
        "  }\n" +
        "}");

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/")
  .post(body)
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/');
$request->setMethod(HTTP_METH_POST);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

$request->setBody('{
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "destination": {
        "geometry": {
            "type": "Point",
            "coordinates": [
                -122.3980960195712,
                37.7930386903944
            ]
        }
    }
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
request.body = {
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "destination": {
        "geometry": {
            "type": "Point",
            "coordinates": [
                -122.3980960195712,
                37.7930386903944
            ]
        }
    }
}.to_json

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let payload = [
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": [
    "geometry": [
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: payload, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSDictionary *payload = @{ @"device_id": @"00112233-4455-6677-8899-AABBCCDDEEFF",
                              @"destination": @{ @"geometry": @{ @"type": @"Point", @"coordinates": @[ @-122.3980960195712, @37.7930386903944 ] } } };

NSData *postData = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Trips with destinations provide routes (using polylines), trip views, and the estimated time of arrival.

To create such a trip, the destination object is required. The object should include a GeoJSON object called geometry. As of right now, only Point is supported in the GeoJSON object, which will set a circular destination point with a radius of 30 meters by default.

HTTP 201 - New trip with destination

{
  "completed_at": null,
  "status": "active",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": null,
    "arrived_at": null,
    "exited_at": null
  },
  "estimate": {
    "arrive_at": "2019-05-03T06:25:51.238000Z",
    "route": {
      "distance": 14666,
      "duration": 2884,
      "remaining_duration": 1560,
      "start_place": "Mannat Manzil #48,2nd cross, 3rd Main,Amrita Nagar, 3rd Phase, Choodasandra, Bengaluru, Karnataka 560035, India",
      "end_place": "4, Muniswamy Garden, A - Block, Bengaluru, Karnataka 560025, India",
      "polyline": {
        "type": "LineString",
        "coordinates": [
          [ -122.3980960195712, 37.7930386903944 ]
          , ... ]
      }
    },
    "reroutes_exceeded": false
  }
}

The Trips API responds with an active trip object. They payload similar to the request but with additional properties.

First, you will notice a views object. Every trip gets assigned unique URLs to share and embed views of the trip. These views show the trip details and device movement only part of the trip (not the entire device movement history).

The URLs will also stay active when the trip was completed. In that case, the views will show a summary of the trip, along with start and end places, distance, duration, arrival time, device info, trip metadata, and the actual route taken to the destination:

trip view

Next, you will notice a new estimate object in the trips payload. HyperTrack provides estimates for every trip with a set destination. The object include information about ...

In order to map the route polyline from the estimates object, you should review the LineString definition of GeoJSON. It provides an array of Point coordinates. Each element is connected to the next, thus creating a pathway to the destination.

To help you understand how to draw polylines on a map, we prepared code samples for Google Maps (JS, Android, iOS) and for Mapbox (JS, Android, iOS).

Track delays for scheduled trips

Run in PostmanPOST https://v3.api.hypertrack.com/trips/

payload='{
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    },
    "scheduled_at": "2022-05-03T06:25:51.238000Z"
  }
}'

curl -X POST \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/ \
  -H 'Content-Type: application/json' \
  -d $payload
const request = require("request");

const payload = {
  device_id: "00112233-4455-6677-8899-AABBCCDDEEFF",
  destination: {
    geometry: {
      type: "Point",
      coordinates: [-122.3980960195712, 37.7930386903944]
    },
    scheduled_at: "2022-05-03T06:25:51.238000Z"
  }
};

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/trips/",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  },
  body: payload
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests
import json

payload = {
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    },
    "scheduled_at": "2022-05-03T06:25:51.238000Z"
  }
}

response = requests.request("POST", "https://v3.api.hypertrack.com/trips/", data=json.dumps(payload).encode("utf-8"), auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType,"{\n" +
        "  \"device_id\": \"00112233-4455-6677-8899-AABBCCDDEEFF\",\n" +
        "  \"destination\": {\n" +
        "    \"geometry\": {\n" +
        "      \"type\": \"Point\",\n" +
        "      \"coordinates\": [-122.3980960195712, 37.7930386903944]\n" +
        "    },\n" +
        "    \"scheduled_at\": \"2022-05-03T06:25:51.238000Z\"\n" +
        "  }\n" +
        "}");

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/")
  .post(body)
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/');
$request->setMethod(HTTP_METH_POST);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

$request->setBody('{
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "destination": {
        "geometry": {
            "type": "Point",
            "coordinates": [
                -122.3980960195712,
                37.7930386903944
            ]
        },
        "scheduled_at": "2022-05-03T06:25:51.238000Z"
    }
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
request.body = {
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "destination": {
        "geometry": {
            "type": "Point",
            "coordinates": [
                -122.3980960195712,
                37.7930386903944
            ]
        },
        "scheduled_at": "2022-05-03T06:25:51.238000Z"
    }
}.to_json

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let payload = [
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": [
    "geometry": [
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    ],
    "scheduled_at": "2019-05-03T06:25:51.238000Z"
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: payload, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSDictionary *parameters = @{ @"device_id": @"00112233-4455-6677-8899-AABBCCDDEEFF",
                              @"destination": @{ @"geometry": @{ @"type": @"Point", @"coordinates": @[ @-122.3980960195712, @37.7930386903944 ] }, @"scheduled_at": @"2022-05-03T06:25:51.238000Z" } };

NSData *postData = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

You can also provide a scheduled_at property (in ISO8601 format) to the destination to indicate a scheduled arrival at the trip destination. This is often used for planned trips with time-sensitive assignments. If set, HyperTrack will send trip delay webhooks as soon as the estimated arrival time surpasses the scheduled time.

HTTP 201 - New trip payload scheduled arrival

{
  "completed_at": null,
  "status": "active",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "metadata": {
    "customer_id": "ABC123"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": "2019-05-03T06:25:51.238000Z",
    "arrived_at": null,
    "exited_at": null
  },
  "estimate": {
    "arrive_at": "2019-05-03T06:25:51.238000Z",
    "route": {
      "distance": 14666,
      "duration": 2884,
      "remaining_duration": 1560,
      "start_place": "Mannat Manzil #48,2nd cross, 3rd Main,Amrita Nagar, 3rd Phase, Choodasandra, Bengaluru, Karnataka 560035, India",
      "end_place": "4, Muniswamy Garden, A - Block, Bengaluru, Karnataka 560025, India",
      "polyline": {
        "type": "LineString",
        "coordinates": [
          [ -122.3980960195712, 37.7930386903944 ]
          , ... ]
      }
    },
    "reroutes_exceeded": false
  }
}

The new trips payload will extend the destination object with arrived_at and exited_at properties. These will be null initially. As soon as the tracked device will enter the destination, the arrival time will be updated. Furthermore, when the device leaves the the destination, the exit time will be set. You can use these properties to identify time spent at a destination.

Track geofence arrival and exit

Run in PostmanPOST https://v3.api.hypertrack.com/trips/

payload='{
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "geofences": [{
    "geometry": {
      "type": "Point",
      "coordinates": [-121.3980960195712, 38.7930386903944]
    },
    "metadata": {
      "stop_id": "12345XYZ",
      "stop_name": "SF office"
    }
  }]
}'

curl -X POST \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/ \
  -H 'Content-Type: application/json' \
  -d $payload
const request = require("request");

const payload = {
  device_id: "00112233-4455-6677-8899-AABBCCDDEEFF",
  geofences: [
    {
      geometry: {
        type: "Point",
        coordinates: [-121.3980960195712, 38.7930386903944]
      },
      metadata: {
        stop_id: "12345XYZ",
        stop_name: "SF office"
      }
    }
  ]
};

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/trips/",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  },
  body: payload
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests
import json

payload = {
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "geofences": [{
    "geometry": {
      "type": "Point",
      "coordinates": [-121.3980960195712, 38.7930386903944]
    },
    "metadata": {
      "stop_id": "12345XYZ",
      "stop_name": "SF office"
    }
  }]
}

response = requests.request("POST", "https://v3.api.hypertrack.com/trips/", data=json.dumps(payload).encode("utf-8"), auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType,"{\n" +
        "  \"device_id\": \"00112233-4455-6677-8899-AABBCCDDEEFF\",\n" +
        "  \"geofences\": [{\n" +
        "    \"geometry\": {\n" +
        "      \"type\": \"Point\",\n" +
        "      \"coordinates\": [-121.3980960195712, 38.7930386903944]\n" +
        "    },\n" +
        "    \"metadata\": {\n" +
        "      \"stop_id\": \"12345XYZ\",\n" +
        "      \"stop_name\": \"SF office\"\n" +
        "    }\n" +
        "  }]\n" +
        "}");

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/")
  .post(body)
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/');
$request->setMethod(HTTP_METH_POST);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

$request->setBody('{
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "geofences": [{
      "geometry": {
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      },
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      }
    }]
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
request.body = {
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "geofences": [{
      "geometry": {
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      },
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      }
    }]
}.to_json

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let payload = [
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "geofences": [
    [
      "geometry": [
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      ],
      "metadata": [
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      ]
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: payload, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSDictionary *payload = @{ @"device_id": @"00112233-4455-6677-8899-AABBCCDDEEFF",
                              @"geofences": @[ @{ @"geometry": @{ @"type": @"Point", @"coordinates": @[ @-121.3980960195712, @38.7930386903944 ] }, @"metadata": @{ @"stop_id": @"12345XYZ", @"stop_name": @"SF office" } } ] };

NSData *postData = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Trips with geofences provide records and notifications for enter and exit into and out of geofenced areas.

To create such a trip, the geofences array is required. The array should include objects with a GeoJSON object called geometry. As of right now, only Point is supported in the GeoJSON object, which will set a circular geofence area with a radius of 30 meters by default.

In order to allow geofence identification and mapping, you can utilize geofence metadata. The metadata will be available through the API, webhooks, and the trips view.

HTTP 201 - New trip with geofences

{
  "completed_at": null,
  "status": "active",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "geofences": [
    {
      "geometry": {
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      },
      "radius": 30,
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      },
      "arrived_at": null,
      "exited_at": null
    }
  ]
}

The Trips API responds with an active trip object. They payload similar to the request but with additional properties.

The trips payload will extend the geofence objects with arrived_at and exited_at properties. These will be null initially. As soon as the tracked device will enter the particular geofence, the arrival time will be updated. Furthermore, when the device leaves the geofence, the exit time will be set. You can use these properties to identify time spent at specific geofences.

Setting trip markers

SDK: Create custom trip marker

[HTSDK setTripMarker:@{ @"custom keys": @"custom values" }
   completionHandler:^(HTSDKCustomEventError * _Nullable error) {
       /// Handle errors here
   }];
HyperTrack.setTripMarker(["custom keys": "custom values"]) { (error) in
    /// Handle errors here
}
// create new marker payload
Map<String,Object> payload = new HashMap<>();

// add event details
payload.put("custom keys", "custom values");

HyperTrack.tripMarker(payload);

To attach contextual data to active trips, HyperTrack provides the ability to set custom trip markers.

To set a trip marker, you need to use the HyperTrack mobile SDK (iOS, Android). There is currently no option to use HyperTrack APIs to set trip markers.

Submitted markers are part of the views and are available in the trip summary as soon as a trip is completed.

Complete active trips

Run in PostmanPOST https://v3.api.hypertrack.com/trips/{trip_id}/complete

curl -X POST \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}/complete
const request = require("request");

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/trips/{trip_id}/complete",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.request("POST", "https://v3.api.hypertrack.com/trips/{trip_id}/complete", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/{trip_id}/complete")
  .post()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/{trip_id}/complete');
$request->setMethod(HTTP_METH_POST);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'

url = URI("https://v3.api.hypertrack.com/trips/{trip_id}/complete")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/{trip_id}/complete")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/{trip_id}/complete"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

By default, active trips will not be automatically marked as completed by HyperTrack - not even after geofence or destination triggers. It is a deliberate decision due to flexbility required by user requirements. Some decide to complete trips on destination enter or on exit, or even after a certain amount of time after the trigger was received.

You should implement your own logic to identify the right timing for trip completion and make the API call, so HyperTrack can complete the trip.

HTTP 202 - Trip completion processing payload

{
  "message": "pending completion for trip '00112233-4455-6677-8899-AABBCCDDEEFF'"
}

It is important to understand that trip completion cannot be confirmed right away with the API response. This is due to communication required between the HyperTrack platform, the mobile SDK on the phone, and post processing to create a trip summary.

Run in PostmanGET https://v3.api.hypertrack.com/trips/{trip_id}

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/trips/{trip_id}",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/trips/{trip_id}", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/{trip_id}")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/{trip_id}');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/{trip_id}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/{trip_id}")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/{trip_id}"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

It usually takes a few seconds to confirm a pending trip completion. As soon as the trip is completed, HyperTrack will send a trip completion webhook. The payload of the webhooks includes the trip ID and metadata.

HTTP 200 - Completed trip payload

{
  "trip_id": "aabb2233-8899-4455-3210-aabbccddeeff",
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "started_at": "2019-05-03T06:25:51.238000Z",
  "completed_at": "2019-05-03T06:25:51.238000Z",
  "status": "completed",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "metadata": {
    "customer_id": "ABC123"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": "2019-05-03T06:25:51.238000Z",
    "arrived_at": "2019-05-03T06:25:51.238000Z"
  },
  "summary": {
     ...
  }
}

With the processed trip completion, the trip summary will be available through the Trips API. The next API call to get the completed trip, the trip status will be completed and a completed_at timestamp will be provided.

The trip object will also be extended with a summary object. This object includes ...

Utilize trip updates

Webhook: Trip created payload

{
  "created_at": "2019-07-01T14:00:00.000000Z",
  "data": {
    "value": "created",
    "trip_id": "123E4567-E89B-12D3-A456-426655440000",
    "trip_metadata": { "customer": "1234" }
  },
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "type": "trip",
  "version": "2.0.0"
}

One of the benefits of trips is the support of webhooks for trip-related activities. Currently, HyperTrack will send notifications triggered by ...

Webhook: Trip destination arrival payload

{
  "created_at": "2019-07-01T14:00:00.000000Z",
  "data": {
    "value": "destination_arrival",
    "trip_id": "123E4567-E89B-12D3-A456-426655440000",
    "trip_metadata": { "customer": "1234" }
  },
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "type": "trip",
  "version": "2.0.0",
  "location": {
    "type": "Point",
    "coordinates": [ -122.39970134375172, 37.7942272665877, -1 ]
  }
}

All trip updates will include the update type, device_id, trip_id and trip_metadata at the very least. More context is provided based on the update type. Please take a look at the trip webhooks references for more details.

It is up to you to decide how to utilize trip updates. To give you an idea, the following can be done:

Get past trips

Run in PostmanGET https://v3.api.hypertrack.com/trips/?status=completed

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/?status=completed?status=completed
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/trips/?status=completed",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/trips/?status=completed", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/?status=completed")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/?status=completed');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/?status=completed")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/?status=completed")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/?status=completed"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

You will notice that the GET /trips endpoint will return only active trips. This is a deliberate design choise to show the most relevant trips, out of potentially thousands of completed trips.

You can set the status path parameter to completed to get past trips.

HTTP 200 - Filter by completed trips

[
  {
    "trip_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "started_at": "2019-05-03T06:25:51.238000Z",
    "completed_at": "2019-05-03T06:25:51.238000Z",
    "status": "completed",
    "views": {
        "embed_url": "https://embed.hypertrack.com/dkdkddnd",
        "share_url": "https://trck.at/abcdef"
    },
    "metadata": {
        "customer_id": "ABC123"
    },
    "destination": {
        "geometry": {
        "type": "Point",
        "coordinates": [
            -122.3980960195712,
            37.7930386903944]
        },
        "radius": 30,
        "scheduled_at": "2019-05-03T06:25:51.238000Z",
        "arrived_at": "2019-05-03T06:25:51.238000Z"
    },
    "summary": {
       ...
    }
  }, ...
]
Review trip summaries

Trips API: Summary available for completed trips

{
  "summary": {
    "locations": {
      "type": "LineString",
      "coordinates": [
        [-122.3996, 37.79396136184457, 123, "2019-09-13T18:21:51.002000Z"],
        [
          -122.39982803643629,
          37.79423869055751,
          null,
          "2019-09-13T18:21:51.802000Z"
        ]
      ]
    },
    "distance": 1234,
    "duration": 9887,
    "started_at": "2019-09-13T18:04:20.467000Z",
    "completed_at": "2019-09-13T20:49:08.226000Z",
    "device_id": "FC772B07-2F27-4EB9-8A3B-F21D7F63A436",
    "markers": [
      {
        "type": "geofence",
        "data": {
          "arrival": {
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:35:51.002000Z"
            }
          },
          "geofence": {
            "geometry": {
              "type": "Point",
              "coordinates": [-122.3996, 37.7939]
            },
            "geofence_id": "7159040c-ad03-4a49-9c1f-11f9763cdf9b",
            "radius": 30,
            "metadata": {
              "stop_id": 2937
            }
          },
          "route_to": {
            "duration": 120,
            "distance": 600,
            "start_location": {
              "geometry": {
                 "type": "Point",
                 "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:33:51.002000Z"
            }
          },
          "exit": {
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:36:51.002000Z"
            }
          },
          "duration": 60
        }
      },
      {
        "type": "device_status",
        "data": {
          "value": "inactive",
          "start": {
            "recorded_at": "2019-09-13T19:40:51.002000Z",
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:39:51.002000Z"
            }
          },
          "end": {
            "recorded_at": "2019-09-13T20:40:51.002000Z",
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T20:40:52.002000Z"
            }
          },
          "reason": "outage.software"
        }
      },
      {
        "type": "trip_marker",
        "data": {
          "recorded_at": "2019-09-13T20:40:52.002000Z",
          "location": {
            "coordinates": [-122.3996, 37.7939],
            "type": "Point"
          },
          "metadata": {
            "id": "1235"
          },
          "route_to": {
            "duration": 2654,
            "distance": 377,
            "start_location": {
              "geometry": {
                 "type": "Point",
                 "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:33:51.002000Z"
            }
          }
        }
      }
    ]
  }
}

For all completed trips, a summary object is provided.

Webhooks

This guide provides an overview of Webhooks for the following HyperTrack features:

About

HyperTrack’s Webhooks allow systems to be notified programmatically about key moments in the movement tracking of their devices, as they happen. To learn the basics of webhook concepts, please read this guide.

Features

The following Webhooks are posted.

Location

Location time series data where each location in the stream includes coordinates and the optional fields speed, altitude, bearing, and accuracy when available.

Device Status

Device status changes. This includes a device becoming active, inactive/disconnected and activity transistions such as start of walk, run, drive, cycle, stop, and moving

Battery

Battery status changes. Values include low, normal and charging

Trips

Trip webhooks always include a creation timestamps (server processed data), a recoding timestamp (device recorded data), device ID, trip ID, and trip details.

Trip creation

For every new trip, creation events are posted.

Destination arrival

Trips destination arrival events are posted when devices enter a specified destination.

Destination exit

Same as arrival events, but posted when devices exit the specified destination.

Trip delays

Trip delay events are posed for trips with a scheduled arrival time. Delay events are send as soon as the estimated time of arrival is past the scheduled time.

Trip completion

For every completed trip, completion events are posted.

Trip markers

Trip markers (formerly "custom events") can be added to the movement data stream by your app. The markers are posted in addition to the movement status (location, activity, device health and more)

Use Cases

Developers use webhooks to build

Architecture

The HyperTrack mobile SDKs send a time-series of events from the device to the HyperTrack server. These events are processed and then posted to your servers on Webhooks. A webhook is an HTTPS POST call from the HyperTrack servers to a configurable destination.

architecture

After receiving a webhook on your own server, you can trigger updates on your mobile or web apps in near real-time and implement your live location features.

Setup

Setting up HyperTrack Webhooks requires configurations on your server and the HyperTrack dashboard. Finally, you need to complete a one-time activation process to verify your identity as the subscriber of the endpoint set on the HyperTrack dashboard. Please ensure you follow all three guidelines to start receiving webhooks.

Server

The server receiving webhooks needs to be configured appropriately to consume webhooks.

Static Endpoint URL

Your server needs to expose a public HTTPS endpoint capable of receiving external, incoming requests. It is important to have a static endpoint URL that will be accessible at all times.

HTTPS POST Method

Webhooks are realized through HTTPS POST requests to the configured endpoint. Your server needs to support this method and be able to parse the payload provided with the request.

JSON Payload

The payload you will receive with POST requests is formatted in JSON. You need to implement the capability to parse JSON objects in order to leverage the HTTP request body content.

You should use a JSON parser that handles converting the escaped representation of control characters back to their ASCII character values (for example, converting \n to a newline character). This is critical if you want to verify the signature of a webhook.

SSL Verification

By default, we verify the SSL certificate of your website when delivering webhook payloads. SSL verification helps ensure that webhooks are delivered to your endpoint URL securely. We only support HTTPS endpoints to ensure secure server-to-server communication.

Make sure that your endpoint has a server certificate from a trusted Certificate Authority (CA). Amazon SNS will only send messages to HTTPS endpoints that have a server certificate signed by a CA trusted by Amazon SNS.

Dashboard

The HyperTrack dashboard allows you add your webhook URL on the Setup page.

setup screen

Just enter your webhook URL and click on "Add Webhook". The screen will ask you to verify your webhook URL to start receiving events. The verification is a one-time activation and described below.

verification pending

One-Time Activation

verification process

Webhook subscription request payload (text/plain)

{
  "Type": "SubscriptionConfirmation",
  "MessageId": "c0216cf3-8f2e-4aae-b678-ccf18a5cb63c",
  "Token": "2336412f37fb687f5d51e6e241dbca52e99b",
  "TopicArn": "arn:aws:sns:us-west-2:012432584802:location_b29fe",
  "Message": "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:012432584802:location_b29fe.\nTo confirm the subscription, visit the SubscribeURL included in this message.",
  "SubscribeURL": "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:012432584802:location_b29fe",
  "Timestamp": "2019-06-11T13:36:08.195Z",
  "SignatureVersion": "1",
  "Signature": "kWr8Z1vgKrN+uS3sOUYTRHTSP3Jhd5cLLWbW9lkBQHgt7JWtAt",
  "SigningCertURL": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-69.pem"
}

As soon as your webhook status is set to ‘Pending verification’, you should notice a confirmation message (HTTPS POST) on your server. The message is coming from the AWS SNS Service HyperTrack is using to handle webhook subscription. The message is in JSON and looks like this:

You should implement your server to handle the subscription confirmation request. You can identify the message type by looking at the HTTPS POST request headers. The relevant header is x-amz-sns-message-type. For the confirmation message above it is set to SubscriptionConfirmation.

To complete the verification, you should read the value for SubscribeURL and visit the URL indicated. You can make an HTTP GET request to the URL either programmatically, by using a command-line tool (cURL), or using a web browser. The request will return an XML document.

Webhook subscription confirmation payload

<ConfirmSubscriptionResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
  <ConfirmSubscriptionResult>
    <SubscriptionArn>arn:aws:sns:us-west-2:012432584802:location_b29fe6c9-27ef-4551-b3ee-8bb3ec000a3b:658eb789-eb17-4694-9575-83b1591df841</SubscriptionArn>
  </ConfirmSubscriptionResult>
  <ResponseMetadata>
    <RequestId>68f77c42-6e72-5e0e-a60a-293905d68d9a</RequestId>
  </ResponseMetadata>
</ConfirmSubscriptionResponse>

The document returns the subscription ARN for the endpoint within the ConfirmSubscriptionResult element. Ensure to store the SubscriptionARN as a string for webhook signature verification (next chapter).

Your one-time verification is now complete and you should start receiving webhooks from HyperTrack. Your dashboard will confirm the completion of this process.

complete setup screen

Receive

With webhooks set up, you will start receiving webhooks from HyperTrack. In this chapter, you will learn how to receive appropriately.

Payload and Headers

Webhooks from HyperTrack will be sent with headers and a JSON payload. Please ensure to verify the headers and implement your server to handle these correctly.

Header: Content-Type

The header is set to text/plain for all webhooks. Please ensure to parse every webhook with this content type. The actual content is represented in JSON.

Header: x-amz-sns-message-type

The header is set to Notification for all webhooks.

Header: x-amz-sns-message-id

The header uniquely identified the webhook. It is important to keep track of the webhook ID because under some circumstances like retries, duplicated webhooks with the same ID could be sent to your server. It is suggested to log most recent webhook IDs to ensure you avoid processing the same update multiple times.

Header: x-amz-sns-subscription-arn

The ARN for the subscription to this URL endpoint. You received this with the subscription confirmation response in XML format during the one-time verification.

JSON Payload

[
  {
    "created_at": "2019-07-01T20:00:01.247377Z",
    "recorded_at": "2019-07-01T20:00:00.000000Z",
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "type": "location",
    "version": "2.0.0",
    "data": {
      // structure based on type of webhook
    }
  }
]

Depending on the type of webhook, the JSON payload will vary. However, the overall structure is fixed.

Currently, the following types are supported:

Feature Type Description
Locations location Location stream
Device Status device_status Device status changes (active, inactive, disconnected and activity changes)
Battery battery Battery changes (low, normal and charging)
Trips trip Trip creation, destination arrival, destination exit, trip delays, and trip completion events

For a complete reference on JSON payload structure, please refer to our Webhook reference.

Responding to webhooks

Make sure to respond to HyperTrack webhooks with the appropriate status code. The connection will time out in 15 seconds. If your endpoint does not respond before the connection times out or if your endpoint returns a status code outside the range of 200–4xx, HyperTrack will consider the delivery of the webhook as a failed attempt and retry as described below.

Retry algorithm

If HyperTrack doesn't receive a successful response from your server, it attempts to deliver the webhook again. By default, if the initial delivery of the webhook fails, HyperTrack attempts up to three retries with a delay between failed attempts set at 20 seconds.

The retries will always refer to the same x-amz-sns-message-id. By comparing the IDs of the webhooks you have processed with incoming webhooks, you can understand whether the message is a retry attempt.

Order of webhooks

HyperTrack will attempt to deliver webhooks in the same order they were received. However, network issues could potentially result in out-of-order webhooks.

Before handling events, you should compare the recorded_at property of the JSON payload and ensure to store events in the order they were recorded as opposed to when they were received.

Process

With a complete setup and webhook receiving in place, you can start processing the actual movement events.

Identifying devices with metadata

In most cases, it is sufficient to use the device_id field to match a device with your own set of records. However, sometimes additional metadata or a readable device name are important.

The mobile SDKs enable you to set a custom device name and attach additional metadata to a device (Android or iOS). If set, you can use the device_id with the Devices API to obtain the metadata. For more details, please read the Devices API usage guide.

In embeddable Hypertrack device views, you can filter by metadata. To learn more about filtering with metadata, read this guide.

Locations

{
  "created_at": "2019-07-01T20:00:01.247377Z",
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "recorded_at": "2019-07-01T20:00:00.000000Z",
  "type": "location",
  "data": {
    "geometry": {
      "type": "Point",
      "coordinates": [-6.2755, 57.6398983, 124]
    },
    "speed": 0.0,
    "bearing": 313.94
  },
  "version": "2.0.0"
}

Location events are sent with a high frequency (~ 100x more than activity events).

Data

Current location of the device in GeoJSON format. Altitude, the optional third parameter in the coordinates array, is the current device elevation in meters, relative to the sea level on iOS and relative to the WGS 84 reference ellipsoid on Android.

Location Accuracy (Optional)

The estimated horizontal accuracy of the location, radial, in meters. When the location identifies the center of a confidence circle, the accuracy defines the radius of the circle (in meters). For Android, there is a 68% probability that the true location is inside the circle.

Bearing (Optional)

The horizontal direction of travel, measured in degrees and relative to true North. Degrees start at true North and continue clockwise around the compass (north is 0, east is 90, south is 180, west is 270 degrees).

Speed (Optional)

Speed of travel in meters per second.

Drawing location streams on a map

Storing past location events will enable you to draw polylines on a map to show the route a device took. Below are code samples for your implementation.

Device status

{
  "created_at": "2019-07-01T20:00:01.247377Z",
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "recorded_at": "2019-07-01T20:00:00.000000Z",
  "type": "device_status",
  "data": {
    "value": "active",
    "activity": "walk"
  },
  "location": {
    "type": "Point",
    "coordinates": [-6.2755, 57.6398983, 124]
  },
  "version": "2.0.0"
}

Device status provides update about the device. The value can be active, inactive and disconnected.

Mobile devices send health data through the Mobile SDKs. The data is showing tracking outages and resumptions. Health data is available for outage events when an outage affects location data. This data is sent with a low frequency (based on device activity).

When the device is active, we include the activity when available. Mobile phones use a variety of sensors combined with location data to intelligently identify phone users’ activity. Activity transitions are sent with a medium frequency (similar to summary events).

Current, HyperTrack supports 6 types of activity transitions: walk, run, drive, cycle, stop, and moving.

Stop and moving are the most general transitions. If the device can classify the activity, it will use the specific type as opposed to the general moving activity transition.

For your convenience, we provide you a set of free-to-use SVG icons to display activities in your application.

Battery updates

{
    "created_at": "2019-07-01T20:00:01.247377Z",
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "recorded_at": "2019-07-01T20:00:00.000000Z",
    "type": "battery",
    "data": {
        "value": "low"
    },
    "location": {
        "type": "Point",
        "coordinates": [-6.2755, 57.6398983 124]
    },
    "version": "2.0.0"
}

HyperTrack sends battery updates to indicate the battery health. These events include details on charge, discharge and low battery.

Trips Updates

{
  "created_at": "2019-07-01T14:00:00.000000Z",
  "data": {
    "value": "created",
    "trip_id": "123E4567-E89B-12D3-A456-426655440000",
    "trip_metadata": { "customer": "1234" }
  },
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "type": "trip",
  "version": "2.0.0"
}

Trip events are posted whenever a trip is started, a specified device enters or exits the destination, a trip with a scheduled arrival is estimated to be delayed, and when a trip is completed. Events provide the device triggering the event, the trip, event type (create, destination enter, destination exit, delay, or completion), and trip metadata defined during creation. Summaries are sent with a medium/low frequency.

Trigger notifications based on trip activity

A common use case is to leverage trip events to trigger contextual, location-aware notifications in web or native applications. To make these types of notifications possible, you should maintain a list of devices (users), a list of trips, and notification templates for trips events (creation, destination enter/exit, completion) to be used as notification message.

It is suggested to leverage device metadata (set through mobile SDKs - Android and iOS) in combination with trips metadata to establish all relevant information in order to send highly contextualized notifications.

SDKs

Android

Please find the nost recent Android SDK guide in the Android Quickstart README.

iOS

Please find the nost recent iOS SDK guide in the iOS Quickstart README.

React Native

Please find the nost recent React Native SDK guide in the React Native Quickstart README.

Views

This guide provides an overview of Views for the following HyperTrack features:

About

HyperTrack’s Views allow to embed and share responsive UIs showing the device and movement data on a map. Using HyperTrack Views removes the need to build your own server to receive, manage and provision live location data to your front-ends. It further removes the need to develop map views.

Features

Views are provided in two variants.

Embed

HyperTrack Views can be embedded to provide the same experience as seen on the HyperTrack Dashboard.

Share

HyperTrack also provides shareable views with limited functionality. Shareable views are intended to be shared with end users to track single trips or single devices of relevance.

Key differences

The key differences between share and embed Views are outlined below.

Feature Share View Embed View
Interaction Responsive views optimized for end users Fully interactive with transitions between views
Available views Single device Devices overview, single device, history overview, single device history
Access control Publically accessible Publishable Key required
Accessibility Short trck.at URL hypertrack.com URL
Sharing Disabled Enabled

Use Cases

Developers use views to build

Architecture

views arhcitecture

HyperTrack Views are implemented in HTML and require JavaScript to run successfully. All views provided are responsive and can be accessed on desktop, tabled, or mobile devices.

While the shareable Views are simple HTML websites with a short URL, embeddable Views require to be integrated into your application using HTML Iframes.

Authentication for embed views

## access requires a publishable key
## replace {publishable_key} with your own key
https://embed.hypertrack.com/devices?publishable_key={publishable_key}

While shareable Views are accessible to everyone with the URL, embed views require the HyperTrack publishable key to work:

Setup

Using HyperTrack Views requires that you:

With access to the HyperTrack dashboard and tracked devices, you can easily obtain sharing URLs and HTML code required to embed Views.

Access shareable views

shareable views can be generated in 3 different ways.

Dashboard share button

## Share button is available on the single device view
https://dashboard.hypertrack.com/devices/{device_id}

share button

The dashboard single device view has a sharing button in the right bottom corner. A click on the button will copy the shareable URL pointing to the live device view.

Devices API

Devices API responses include a views property with a share_url. More details can be found in the Devices API reference.

Trips API

Just like the Devices API, HyperTrack generates live views for active trips. More details can be found in the Trips API reference.

Embed views

Similar to shareable views, there are 3 ways to get URLs for embeddable Views.

Dashboard code button

## Coding view instructions
const baseUrl = "https://embed.hypertrack.com/devices"
const publishableKey = "xyz"

## Embeddable widget for Get Devices Status
<iframe width="400px" height="400px" src=`{baseUrl}?publishable_key={publishableKey}` />

code button

For every view that can be embedded, you will find a <-> Code button on the top right corner of the view. Clicking on that button will unfold a syntax-highlighted coding view with instructions to embed the current view.

The following dashboard views have the code button at this time:

Inline Frames

Embeddable views are implemented with HTML inline frames and require JavaScript to be executed successfully.

Iframes have important properties to be considered during implementation. Please read the following instructions carefully to ensure a seamless integration:

Devices API

Devices API responses include a views property with an embed_url. More details can be found in the Devices API reference.

Trips API

Just like the Devices API, HyperTrack generates embeddable views for active trips. More details can be found in the Trips API reference.

Web

Embed

Map view
## Devices Overview URL
https://embed.hypertrack.com/devices

map view

The map view shows a map with a list of all available devices, grouped by device status. For every device that provided a location in the past, a dot will be displayed on the map. A click on the device in the list will zoom into the last known location on the map. It will also open a device status popup (see below). Another click on the dot will open up the single device view.

device status popup

The device status popup provides the following details:

Review device status

In the list view, devices are grouped by active, inactive, and disconnected. Below is a description of the classification.

devices list

Active: The device is actively sending movement data to HyperTrack systems. Active devices are represented with a green dot on the live map.

Inactive: The device cannot send movement data to HyperTrack systems for known reasons (also referred to as outage). Inactive devices are represented with a gray dot on the live map and the inactive icon icon in the device overview.

Disconnected: The device is expected to send data to HyperTrack systems but it hasn’t been for over an hour. HyperTrack systems are usually able to understand and report the reason for the disconnect when the device reconnects. Disconnected devices are represented with a gray dot on the live map and the disconnected icon icon in the device overview.

List view

The list view is built for analyzing and comparing your device's events during a time range. A device's tracking, trips, geofence, destination, trip markers, and activity data can be sorted and ranked. It is timezone aware as well, allowing you to view your worldwide location data easily.

list view

Visits: Time spent in / traveling to destinations / geofences

Trip Markers: Time spent / distance traveling to trip markers

Duration: Time spent active / inactive / disconnected

Stops: Time spent at a stop

Walks: Distance traveled / time spent walking

Drives: Distance traveled / time spent driving

list view

You can select a date range and timezone with their respective dropdowns.

Filter by metadata
[
  { "device_id": "1",
    "metadata": {
        "person_name": "Alex",
        "vehicle_type": "bike",
        "group_id": 3
    }
  },
  { "device_id": "2",
    "metadata": {
        "person_name": "Kishan",
        "vehicle_type": "scooter",
        "group_id": 1
    }
  },
  { "device_id": "3",
    "metadata": {
        "person_name": "Kaitlin",
        "vehicle_type": "scooter",
        "group_id": 3
    }
  },
  ...
]

Device metadata can be used to create restricted views for subsets of your tracked devices. To learn more about how to set metadata via our SDKs, please read this guide.

If you have metadata attached to your devices, you can filter the embedded view to include devices with specified keys and values. In the example, devices have metadata about the vehicle_type they use to get around. If we were to filter devices by {"vehicle_type":"scooter"}, only devices with vehicle_type equal to scooter will show.

devices list metadata device metadata

## Coding view instructions
const baseUrl = "https://embed.hypertrack.com/devices"
const publishableKey = "xyz"

const metadataObject = {
  vehicle_type: "scooter"
}
const metadataFilter = JSON.stringify(metadataObject)

## Embeddable widget for Get Devices Status by metadata
<iframe width="400px" height="400px" src=`{baseUrl}?metadata_filter={metadataFilter}&publishable_key={publishableKey}` />

The metadata filter is passed to the embed view URL by query string parameter named metadata_filter. Only valid JSON strings can be passed to the URL, and your objects must have a max nesting depth of 1. While testing, you can use this linter to validate JSON.

Your browser will most likely encode { } and : special characters, but when distributing embed URLs with a metadata_filter, be sure to encode your link. To read more about URL encoding, please read this guide.

Live device view
## Live Device View URL
https://embed.hypertrack.com/devices/{device_id}

live device view

The live device view shows a map with the last known locations of the selected device. For every location update since the opening of the view, a new dot will be placed on the map to show the route of the device.

For the most recent location update, the green dot (with a white outline) can have different styles to convey additional information:

Review device details

device details

The device details popup shows a summary of all known device and movement attributes:

A click on the information icon next to the device name/ID will display further device details, including:

Device history view
## Device History View URL
https://embed.hypertrack.com/devices

device history view

The single device history view shows a map of the location and activity data. The map shows a green dot for every location update and an activity icon for every activity update. You can click on every dot to see further details on the update.

To access the single device history view from within the HyperTrack dashboard, you can navigate to the single device view. You should see a history button in the bottom right corner:

history button

Identify activity changes

A click on the location or activity update will open up a popup with further details:

activity button

The following details are listed in the popup:

For your convenience, the popup provides a feature to copy the details of the update. A click on <-> Copy Data will store one of the following JSON in your clipboard (depending on the update type).

Activity update data

{
  "device_id": "704C6AE3-C298-4608-B330-A18ADA20B34F",
  "recorded_at": "2019-07-01T15:01:02.690000Z",
  "type": "activity",
  "pedometer": {
    "time_delta": 5106,
    "number_of_steps": 56
  },
  "value": "cycle",
  "index": 103,
  "timezone": "America/Los_Angeles"
}
Field Type Description
device_id string Unique identifier representing a device, case sensitive
recorded_at string Timestamp for the location of activity update
type string Defines the structure of the JSON object. Can be one of location or activity.
pedometer object Step tracking data. Only available for activities other than stop.
pedometer.time_delta int Time of activity in seconds
pedometer.number_of_steps int Number of steps in this activity
value string Activity type. Can be one of stop, walk, run, drive, or cycle (more details).
index int Counter of activity updates since initialization of the device?
timezone string The timezone on the device in TZ format

Location update data

{
  "device_id": "704C6AE3-C298-4608-B330-A18ADA20B34F",
  "recorded_at": "2019-07-01T14:59:00.997000Z",
  "type": "location",
  "speed": 12.280691501233681,
  "location": {
    "type": "Point",
    "coordinates": [37.868282261644616, -122.28401381798933]
  },
  "accuracy": 14.97022062435497,
  "bearing": 1.5546167296350293,
  "altitude": 24.362770905499346,
  "timezone": "America/Los_Angeles"
}
Field Type Description
device_id string Unique identifier representing a device, case sensitive
recorded_at string Timestamp for the location of activity update
type string Defines the structure of the JSON object. Can be one of location or activity.
speed float Speed of travel in meters per second
location object GeoJSON with Point type
accuracy float Accuracy in meters
bearing float The horizontal direction of travel in degrees (more details)
altitude float Device elevation in meters
timezone string The timezone on the device in TZ format

Share

Live device view

## Tracking URL
https://trck.at/{tracking_id}

live device view share

As described in the setup chapter, you can obtain a tracking URL in various ways. Once opened, the shared view will display the live device view with limited functionality (no interaction to other screens like history and no sharing capability).

Native

Apart from ready-to-use views for web usage, native libraries are available to consume HyperTrack data directly in your iOS and Android app.

HyperTrack Views libraries are used for getting live location and movement data for devices and trips directly to your native app. These libraries subscribe to HyperTrack GraphQL interfaces to get data streams and exposes them through useful callbacks. This helps developers create custom live location views and go serverless. Their app users can directly get data securely and privately from the HyperTrack servers.

Follow the iOS or Android Quickstarts to implement your custom views powered by HyperTrack data.

References

APIs

Devices

Manage devices on the HyperTrack platform.

GET /devices

Run in PostmanGET https://v3.api.hypertrack.com/devices/

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/devices/
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/devices/",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/devices/", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/devices/")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/devices/');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/devices/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/devices/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/devices/"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

HTTP 200 - Devices payload

[
  {
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "location": {
        "speed": 4.20,
        "accuracy": 14.09,
        "bearing": 193.12,
        "geometry": {
        "type": "Point",
        "coordinates": [
            35.1016383,
            47.8391314,
            65.40
        ]
        },
        "recorded_at": "2019-07-18T18:01:59.064000Z",
    },
    "device_status": {
        "data": {
        "recorded_at": "2019-07-30T01:38:45.610000Z",
        "activity": "stop"
        },
        "value": "active"
    },
    "views": {
        "share_url":"https://trck.at/abcdef",
        "embed_url":"https://embed.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF?publishable_key=abc"
    },
    "battery": "normal",
    "device_info": {
        "timezone": "America/Los_Angeles",
        "os_name": "iOS",
        "device_brand": "Apple",
        "sdk_version": "3.3.2",
        "device_model": "iPhone X",
        "network_operator": "T-Mobile",
        "name": "Alex’s Phone",
        "os_version": "12.4"
    },
    "registered_at": "2019-07-10T01:38:45.610000Z",
    "metadata": { ... }
  },
  ...
]

Get all tracked devices.

Authentication: Basic Auth

Response Attributes

Name Type Description
device_id string Unique device identifier, case sensitive
location object (optional)
location.data.speed float (optional) speed in m/s
location.data.accuracy float (optional) accuracy in m
location.data.bearing float (optional) bearing in degrees starting at due north and continuing clockwise around the compass
location.data.geometry object Location in GeoJSON format
location.data.geometry.type string As of right now, only Point is supported
location.data.geometry.coordinates array Array of longitude, latitude and optional altitude
location.recorded_at string ISO 8601 date when the location was recorded
device_status object Device status
device_status.value string Can be one of active, inactive and disconnected. More details
device_status.data object Extra information about device status
device_status.data.recorded_at string ISO 8601 date when the device status was recorded (optional)
device_status.data.activity string Device activity (optional). If available, can be one of stop, walk, run, cycle, or drive
device_status.data.reason string Reason of inactivity (optional). For inactive devices only. Can be one of location_permissions_denied, motion_activity_permissions_denied, location_services_disabled, motion_activity_services_disabled, motion_activity_services_unavailable, or stopped_programmatically
views object
views.embed_url string Embeddable view URL
views.share_url string Sharable view URL
battery string Battery status, can be one of low, normal, or charging
device_info object Device information
device_info.timezone string The timezone on the device in TZ format
device_info.os_name string The operating system of the device, can be one of iOS or Android
device_info.device_brand string The brand of the device
device_info.sdk_version string The HyperTrack SDK version on the device. Can be reviewed here: Android, iOS, React Native
device_info.device_model string The device model
device_info.network_operator string The network operator for the device
device_info.os_version string The version of the operating system on the device
metadata object Device metadata submitted via Mobile SDKs (Android, iOS) or Devices API
registered_at string ISO 8601 date when the device was registered
name object The name of the device submitted via Mobile SDKs (Android, iOS) or Devices API

GET /devices/{device_id}

Run in PostmanGET https://v3.api.hypertrack.com/devices/{device_id}

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/devices/{device_id}
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/devices/{device_id}",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/devices/{device_id}", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/devices/{device_id}")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/devices/{device_id}');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/devices/{device_id}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/devices/{device_id}")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/devices/{device_id}"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

HTTP 200 - Single device payload

{
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "location": {
    "speed": 4.20,
    "accuracy": 14.09,
    "bearing": 193.12,
    "geometry": {
      "type": "Point",
      "coordinates": [
        35.1016383,
        47.8391314,
        65.40
      ]
    },
    "recorded_at": "2019-07-18T18:01:59.064000Z",
  },
  "device_status": {
    "data": {
      "recorded_at": "2019-07-30T01:38:45.610000Z",
      "activity": "stop"
    },
    "value": "active"
  },
  "views": {
    "share_url":"https://trck.at/abcdef",
    "embed_url":"https://embed.hypertrack.com/devices/00112233-4455-6677-8899-AABBCCDDEEFF?publishable_key=abc"
  },
  "battery": "normal",
  "device_info": {
    "timezone": "America/Los_Angeles",
    "os_name": "iOS",
    "device_brand": "Apple",
    "sdk_version": "3.3.2",
    "device_model": "iPhone X",
    "network_operator": "T-Mobile",
    "name": "Alex’s Phone",
    "os_version": "12.4"
  },
  "registered_at": "2019-07-10T01:38:45.610000Z",
  "metadata": { ... }
}

Get a single device.

Authentication: Basic Auth

Path Parameters

device_id - a string representing the ID of a tracked device, case sensitive

Response Attributes

Name Type Description
device_id string Unique device identifier, case sensitive
location object (optional)
location.data.speed float (optional) speed in m/s
location.data.accuracy float (optional) accuracy in m
location.data.bearing float (optional) bearing in degrees starting at due north and continuing clockwise around the compass
location.data.geometry object Location in GeoJSON format
location.data.geometry.type string As of right now, only Point is supported
location.data.geometry.coordinates array Array of longitude, latitude and optional altitude
location.recorded_at string ISO 8601 date when the location was recorded
device_status object Device status
device_status.value string Can be one of active, inactive and disconnected. More details
device_status.data object Extra information about device status
device_status.data.recorded_at string ISO 8601 date when the device status was recorded (optional)
device_status.data.activity string Device activity (optional). If available, can be one of stop, walk, run, cycle, or drive
device_status.data.reason string Reason of inactivity (optional). For inactive devices only. Can be one of location_permissions_denied, motion_activity_permissions_denied, location_services_disabled, motion_activity_services_disabled, motion_activity_services_unavailable, or stopped_programmatically
views object
views.embed_url string Embeddable view URL
views.share_url string Sharable view URL
battery string Battery status, can be one of low, normal, or charging
device_info object Device information
device_info.timezone string The timezone on the device in TZ format
device_info.os_name string The operating system of the device, can be one of iOS or Android
device_info.device_brand string The brand of the device
device_info.sdk_version string The HyperTrack SDK version on the device. Can be reviewed here: Android, iOS, React Native
device_info.device_model string The device model
device_info.network_operator string The network operator for the device
device_info.os_version string The version of the operating system on the device
metadata object Device metadata submitted via Mobile SDKs (Android, iOS) or Devices API
registered_at string ISO 8601 date when the device was registered
name object The name of the device submitted via Mobile SDKs (Android, iOS) or Devices API

PATCH /devices/{device_id}

Run in PostmanPATCH https://v3.api.hypertrack.com/devices/{device_id}

payload='{
  "name": "Alex’s Phone",
  "metadata": {
    "customer_id": "ABC123"
  }
}'

curl -X PATCH \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/devices/{device_id} \
  -H 'Content-Type: application/json' \
  -d $payload
const request = require("request");

const payload = {
  name: "Alex’s Phone",
  metadata: {
    customer_id: "ABC123"
  }
};

const options = {
  method: "PATCH",
  url: "https://v3.api.hypertrack.com/devices/{device_id}",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  },
  body: payload
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests
import json

payload = {
  "name": "Alex’s Phone",
  "metadata": {
    "customer_id": "ABC123"
  }
}

response = requests.request("PATCH", "https://v3.api.hypertrack.com/devices/{device_id}", data=json.dumps(payload).encode("utf-8"), auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  "
    + "\"name\": \"Alex’s Phone\",\n "
    + "  \"metadata\": {\n"
    + "    \"customer_id\": \"ABC123\"\n"
    + "  }\n"
    + "}");

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/devices/{device_id}")
  .patch(body)
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/devices/{device_id}');
$request->setMethod(HTTP_METH_PATCH);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

$request->setBody('{
  "name": "Alex’s Phone",
  "metadata": {
    "customer_id": "ABC123"
  }
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/devices/{device_id}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
request.body = {
  "name": "Alex’s Phone",
  "metadata": {
    "customer_id": "ABC123"
  }
}.to_json

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let payload = [
  "name": "Alex’s Phone",
  "metadata": ["customer_id": "ABC123"]
] as [String : Any]

let patchData = JSONSerialization.data(withJSONObject: payload, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/devices/{device_id}")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
request.allHTTPHeaderFields = headers
request.httpBody = patchData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSDictionary *payload = @{ @"name": @"Alex’s Phone",
                              @"metadata": @{ @"customer_id": @"ABC123" } };

NSData *patchData = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/devices/{device_id}"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"PATCH"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:patchData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

HTTP 204 - Device updated (no content)

Update a single device's name and/or metadata.

Authentication: Basic Auth

Path Parameters

device_id - a string representing the ID of a tracked device, case sensitive

DELETE /devices/{device_id}

Run in PostmanDELETE https://v3.api.hypertrack.com/devices/{device_id}

curl -X DELETE \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/devices/{device_id}
const request = require("request");

const options = {
  method: "DELETE",
  url: "https://v3.api.hypertrack.com/devices/{device_id}",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.request("DELETE", "https://v3.api.hypertrack.com/devices/{device_id}", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/devices/{device_id}")
  .delete(null)
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/devices/{device_id}');
$request->setMethod(HTTP_METH_DELETE);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/devices/{device_id}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Delete.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/devices/{device_id}")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "DELETE"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/devices/{device_id}"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"DELETE"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

HTTP 204 - Device removed (no content)

Remove a single device. If the same devices starts to send location data after the removal, it will be added back to the list.

Authentication: Basic Auth

Path Parameters

device_id - a string representing the ID of a tracked device, case sensitive

Trips

Manage Trips on the HyperTrack platform.

POST /trips

Run in PostmanPOST https://v3.api.hypertrack.com/trips/

payload='{
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    },
    "scheduled_at": "2022-05-03T06:25:51.238000Z"
  },
  "geofences": [
    {
      "geometry": {
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      },
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      }
    }
  ],
  "metadata": {
    "shift_id": "ABC123"
  }
}'

curl -X POST \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/ \
  -H 'Content-Type: application/json' \
  -d $payload
const request = require("request");

const payload = {
  device_id: "00112233-4455-6677-8899-AABBCCDDEEFF",
  destination: {
    geometry: {
      type: "Point",
      coordinates: [-122.3980960195712, 37.7930386903944]
    },
    scheduled_at: "2022-05-03T06:25:51.238000Z"
  },
  geofences: [
    {
      geometry: {
        type: "Point",
        coordinates: [-121.3980960195712, 38.7930386903944]
      },
      metadata: {
        stop_id: "12345XYZ",
        stop_name: "SF office"
      }
    }
  ],
  metadata: {
    shift_id: "ABC123"
  }
};

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/trips/",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  },
  body: payload
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests
import json

payload = {
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    },
    "scheduled_at": "2022-05-03T06:25:51.238000Z"
  },
  "geofences": [
    {
      "geometry": {
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      },
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      }
    }
  ],
  "metadata": {
    "shift_id": "ABC123"
  }
}

response = requests.request("POST", "https://v3.api.hypertrack.com/trips/", data=json.dumps(payload).encode("utf-8"), auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType,"{\n" +
        "  \"device_id\": \"00112233-4455-6677-8899-AABBCCDDEEFF\",\n" +
        "  \"destination\": {\n" +
        "    \"geometry\": {\n" +
        "      \"type\": \"Point\",\n" +
        "      \"coordinates\": [-122.3980960195712, 37.7930386903944]\n" +
        "    },\n" +
        "    \"scheduled_at\": \"2022-05-03T06:25:51.238000Z\"\n" +
        "  },\n" +
        "  \"geofences\": [\n" +
        "    {\n" +
        "      \"geometry\": {\n" +
        "        \"type\": \"Point\",\n" +
        "        \"coordinates\": [-121.3980960195712, 38.7930386903944]\n" +
        "      },\n" +
        "      \"metadata\": {\n" +
        "        \"stop_id\": \"12345XYZ\",\n" +
        "        \"stop_name\": \"SF office\"\n" +
        "      }\n" +
        "    }\n" +
        "  ],\n" +
        "  \"metadata\": {\n" +
        "    \"shift_id\": \"ABC123\"\n" +
        "  }\n" +
        "}");

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/")
  .post(body)
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/');
$request->setMethod(HTTP_METH_POST);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

$request->setBody('{
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "destination": {
        "geometry": {
            "type": "Point",
            "coordinates": [
                -122.3980960195712,
                37.7930386903944
            ]
        },
        "scheduled_at": "2022-05-03T06:25:51.238000Z"
    },
    "geofences": [
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -121.3980960195712,
                    38.7930386903944
                ]
            },
            "metadata": {
                "stop_id": "12345XYZ",
                "stop_name": "SF office"
            }
        }
    ],
    "metadata": {
        "shift_id": "ABC123"
    }
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp
request.body = {
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "destination": {
        "geometry": {
            "type": "Point",
            "coordinates": [
                -122.3980960195712,
                37.7930386903944
            ]
        },
        "scheduled_at": "2022-05-03T06:25:51.238000Z"
    },
    "geofences": [
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -121.3980960195712,
                    38.7930386903944
                ]
            },
            "metadata": {
                "stop_id": "12345XYZ",
                "stop_name": "SF office"
            }
        }
    ],
    "metadata": {
        "shift_id": "ABC123"
    }
}.to_json

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let payload = [
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "destination": [
    "geometry": [
      "type": "Point",
      "coordinates": [-122.3980960195712, 37.7930386903944]
    ],
    "scheduled_at": "2019-05-03T06:25:51.238000Z"
  ],
  "geofences": [
    [
      "geometry": [
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      ],
      "metadata": [
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      ]
    ]
  ],
  "metadata": ["shift_id": "ABC123"]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: payload, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSDictionary *payload = @{ @"device_id": @"00112233-4455-6677-8899-AABBCCDDEEFF",
                              @"destination": @{ @"geometry": @{ @"type": @"Point", @"coordinates": @[ @-122.3980960195712, @37.7930386903944 ] }, @"scheduled_at": @"2019-05-03T06:25:51.238000Z" },
                              @"geofences": @[ @{ @"geometry": @{ @"type": @"Point", @"coordinates": @[ @-121.3980960195712, @38.7930386903944 ] }, @"metadata": @{ @"stop_id": @"12345XYZ", @"stop_name": @"SF office" } } ],
                              @"metadata": @{ @"shift_id": @"ABC123" } };

NSData *postData = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Create a new trip for a device.

Authentication: Basic Auth

Request Attributes

Name Type Description
device_id string Unique identifier representing a device, case sensitive
destination object Definition of a trip destination (optional)
destination.geometry object GeoJSON geometry of type Point
destination.geometry.type string As of right now, only Point is supported
destination.geometry.coordinates array Array of longitude and latitude (in that order)
destination.radius int Defines the radius (in meters) of a circular trip destination (optional, default is 30)
destination.scheduled_at string Timestamp for scheduled arrival (optional)
geofences array Array of geofence objects (optional)
geofences[].geometry object GeoJSON geometry of type Point
geofences[].geometry.type string As of right now, only Point is supported
geofences[].geometry.coordinates array Array of longitude and latitude
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30)
geofences[].metadata object Any metadata you want to assign to this geofence (optional)
metadata object Any metadata you want to assign to this trip (optional)

HTTP 201 - New trip payload

{
  "completed_at": null,
  "status": "active",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "metadata": {
    "customer_id": "ABC123"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": "2019-05-03T06:25:51.238000Z",
    "arrived_at": null,
    "exited_at": null
  },
  "geofences": [
    {
      "geometry": {
        "type": "Point",
        "coordinates": [-121.3980960195712, 38.7930386903944]
      },
      "radius": 30,
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      },
      "arrived_at": null,
      "exited_at": null
    }
  ],
  "estimate": {
    "arrive_at": "2019-05-03T06:25:51.238000Z",
    "route": {
      "distance": 14666,
      "duration": 2884,
      "remaining_duration": 1560,
      "start_place": "Mannat Manzil #48,2nd cross, 3rd Main,Amrita Nagar, 3rd Phase, Choodasandra, Bengaluru, Karnataka 560035, India",
      "end_place": "4, Muniswamy Garden, A - Block, Bengaluru, Karnataka 560025, India",
      "polyline": {
        "type": "LineString",
        "coordinates": [
          [ -122.3980960195712, 37.7930386903944 ]
          , ... ]
      }
    },
    "reroutes_exceeded": false
  }
}

Response Attributes

Name Type Description
trip_id string Unique identifier of the newly created trip, case sensitive
device_id string Unique identifier of the device associated with the trip, case sensitive
started_at string Timestamp for trip starting time
completed_at string Timestamp of trip completion time (only set when trip is completed), can be null
status string Trip status, can be active, completed or processing_completion
views.embed_url string Embeddable trip view
views.share_url string Shareable trip view
destination object Defined trip destination
destination.geometry object GeoJSON geometry of type Point for destination point
destination.radius int Radius (in meters) of a circular trip destination
destination.scheduled_at string Timestamp for scheduled arrival
destination.arrived_at string Timestamp first enter to destination
destination.exited_at string Timestamp first exit from destination
geofences array Array of geofence objects (optional)
geofences[].geometry object GeoJSON geometry of type Point
geofences[].geometry.type string As of right now, only Point is supported
geofences[].geometry.coordinates array Array of longitude and latitude
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30)
geofences[].metadata object Any metadata you want to assign to this geofence (optional)
geofences[].arrived_at string Timestamp first enter to geofence
geofences[].exited_at string Timestamp first exit from geofence
estimate object Estimates (route and arrival time) Only available for active trips.
estimate.arrive_at string Timestamp for estimated arrival
estimate.route objects Planned route segments to destination
estimate.route.distance int Route distance in meters
estimate.route.duration int Route duration in seconds
estimate.route.remaining_duration int Remaining route duration in seconds, can be null
estimate.route.start_place string Start place for segment start
estimate.route.end_place string End place for segment end
estimate.route.polyline object GeoJSON geometry of type LineString
estimate.reroutes_exceeded boolean Indicates if re-route limit of 10 was exceeded
metadata object Metadata provided at trip creation

Please keep in mind that new trips do not have the summary property (outlining the trip history). The summary is only provided upon completion of a trip.

GET /trips

Run in PostmanGET https://v3.api.hypertrack.com/trips/

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/trips/",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/trips/", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Get all trips. This endpoint return active trips by default.

Authentication: Basic Auth

Query Parameters

status - (optional) a string representing the trip status to filter by. Default is active.

HTTP 200 - Trips payload

{
  "data":[
    {
      "trip_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
      "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
      "started_at": "2019-05-03T06:25:51.238000Z",
      "completed_at": null,
      "status": "active",
      "views": {
          "embed_url": "https://embed.hypertrack.com/dkdkddnd",
          "share_url": "https://trck.at/abcdef"
      },
      "metadata": {
          "customer_id": "ABC123"
      },
      "destination": {
          "geometry": {
          "type": "Point",
          "coordinates": [
              -122.3980960195712,
              37.7930386903944]
          },
          "radius": 30,
          "scheduled_at": "2019-05-03T06:25:51.238000Z",
          "arrived_at": null,
          "exited_at": null
      },
      "geofences": [{
          "geometry": {
              "type": "Point",
              "coordinates": [-121.3980960195712, 38.7930386903944]
          },
          "radius": 30,
          "metadata": {
              "stop_id": "12345XYZ",
              "stop_name": "SF office"
          },
          "arrived_at": null,
          "exited_at": null
      }],
      "estimate": {
          "arrive_at": "2019-05-03T06:25:51.238000Z",
          "route": {
              "distance": 14666,
              "duration": 2884,
              "remaining_duration": 1560,
              "start_place": "Mannat Manzil #48,2nd cross, 3rd Main,Amrita Nagar, 3rd Phase, Choodasandra, Bengaluru, Karnataka 560035, India",
              "end_place": "4, Muniswamy Garden, A - Block, Bengaluru, Karnataka 560025, India",
              "polyline": {
                  "type": "LineString",
                  "coordinates": [
                  [ -122.3980960195712, 37.7930386903944 ]
                  , ... ]
              }
          },
          "reroutes_exceeded": false
      }
    },
    {
      "trip_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
      "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
      "started_at": "2019-05-03T06:25:51.238000Z",
      "completed_at": "2019-05-03T06:25:51.238000Z",
      "status": "completed",
      "views": {
          "embed_url": "https://embed.hypertrack.com/dkdkddnd",
          "share_url": "https://trck.at/abcdef"
      },
      "metadata": {
          "customer_id": "ABC123"
      },
      "destination": {
          "geometry": {
          "type": "Point",
          "coordinates": [
              -122.3980960195712,
              37.7930386903944]
          },
          "radius": 30,
          "scheduled_at": "2019-05-03T06:25:51.238000Z",
          "arrived_at": "2019-05-03T06:25:51.238000Z"
      },
      "summary": {
          ...
      }
    }, ...
  ],
  "links":{
    "next": "https://v3.api.hypertrack.com/trips/?pagination_token=abc"
  }
}

Response Attributes

Name Type Description
trip_id string Unique identifier of the newly created trip, case sensitive
device_id string Unique identifier of the device associated with the trip, case sensitive
started_at string Timestamp for trip starting time
completed_at string Timestamp of trip completion time (only set when trip is completed), can be null
status string Trip status, can be active, completed or processing_completion
views.embed_url string Embeddable trip view
views.share_url string Shareable trip view
destination object Defined trip destination
destination.geometry object GeoJSON geometry of type Point for destination point
destination.radius int Radius (in meters) of a circular trip destination
destination.scheduled_at string Timestamp for scheduled arrival
destination.arrived_at string Timestamp first enter to destination
destination.exited_at string Timestamp first exit from destination
geofences array Array of geofence objects (optional)
geofences[].geometry object GeoJSON geometry of type Point
geofences[].geometry.type string As of right now, only Point is supported
geofences[].geometry.coordinates array Array of longitude and latitude
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30)
geofences[].metadata object Any metadata you want to assign to this geofence (optional)
geofences[].arrived_at string Timestamp first enter to geofence
geofences[].exited_at string Timestamp first exit from geofence
estimate object Estimates (route and arrival time). Only available for active trips.
estimate.arrive_at string Timestamp for estimated arrival
estimate.route objects Planned route segments to destination
estimate.route.distance int Route distance in meters
estimate.route.duration int Route duration in seconds
estimate.route.remaining_duration int Remaining route duration in seconds, can be null
estimate.route.start_place string Start place for segment start
estimate.route.end_place string End place for segment end
estimate.route.polyline object GeoJSON geometry of type LineString
estimate.reroutes_exceeded boolean Indicates if re-route limit of 10 was exceeded
summary object Trip summary. Only available for completed trips.
metadata object Metadata provided at trip creation

GET /trips/{trip_id}

Run in PostmanGET https://v3.api.hypertrack.com/trips/{trip_id}

curl \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}
const request = require("request");

const options = {
  url: "https://v3.api.hypertrack.com/trips/{trip_id}",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.get("https://v3.api.hypertrack.com/trips/{trip_id}", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "{AccountId}","{SecretKey}")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/{trip_id}")
  .get()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/{trip_id}');
$request->setMethod(HTTP_METH_GET);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'
require 'json'

url = URI("https://v3.api.hypertrack.com/trips/{trip_id}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/{trip_id}")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/{trip_id}"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Get a single trip.

Authentication: Basic Auth

Path Parameters

trip_id - a string representing the ID of a trip, case sensitive

HTTP 200 - Completed trip payload

{
  "trip_id": "aabb2233-8899-4455-3210-aabbccddeeff",
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "started_at": "2019-05-03T06:25:51.238000Z",
  "completed_at": "2019-05-03T06:25:51.238000Z",
  "status": "completed",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "metadata": {
    "customer_id": "ABC123"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": "2019-05-03T06:25:51.238000Z",
    "arrived_at": "2019-05-03T06:25:51.238000Z"
  },
  "summary": {
     ...
  }
}

Response Attributes

Name Type Description
trip_id string Unique identifier of the newly created trip, case sensitive
device_id string Unique identifier of the device associated with the trip, case sensitive
started_at string Timestamp for trip starting time
completed_at string Timestamp of trip completion time (only set when trip is completed), can be null
status string Trip status, can be active, completed or processing_completion
views.embed_url string Embeddable trip view
views.share_url string Shareable trip view
destination object Defined trip destination
destination.geometry object GeoJSON geometry of type Point for destination point
destination.radius int Radius (in meters) of a circular trip destination
destination.scheduled_at string Timestamp for scheduled arrival
destination.arrived_at string Timestamp first enter to destination
destination.exited_at string Timestamp first exit from destination
geofences array Array of geofence objects (optional)
geofences[].geometry object GeoJSON geometry of type Point
geofences[].geometry.type string As of right now, only Point is supported
geofences[].geometry.coordinates array Array of longitude and latitude
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30)
geofences[].metadata object Any metadata you want to assign to this geofence (optional)
geofences[].arrived_at string Timestamp first enter to geofence
geofences[].exited_at string Timestamp first exit from geofence
estimate object Estimates (route and arrival time). Only available for active trips.
estimate.arrive_at string Timestamp for estimated arrival
estimate.route objects Planned route segments to destination
estimate.route.distance int Route distance in meters
estimate.route.duration int Route duration in seconds
estimate.route.remaining_duration int Remaining route duration in seconds, can be null
estimate.route.start_place string Start place for segment start
estimate.route.end_place string End place for segment end
estimate.route.polyline object GeoJSON geometry of type LineString
estimate.reroutes_exceeded boolean Indicates if re-route limit of 10 was exceeded
summary object Trip summary. Only available for completed trips.
metadata object Metadata provided at trip creation

For completed trips, the response will include summary object giving location and marker details about the full trip.

Trips API: Summary available for completed trips

{
  "summary": {
    "locations": {
      "type": "LineString",
      "coordinates": [
        [-122.3996, 37.79396136184457, 123, "2019-09-13T18:21:51.002000Z"],
        [
          -122.39982803643629,
          37.79423869055751,
          null,
          "2019-09-13T18:21:51.802000Z"
        ]
      ]
    },
    "distance": 1234,
    "duration": 9887,
    "started_at": "2019-09-13T18:04:20.467000Z",
    "completed_at": "2019-09-13T20:49:08.226000Z",
    "device_id": "FC772B07-2F27-4EB9-8A3B-F21D7F63A436",
    "markers": [
      {
        "type": "geofence",
        "data": {
          "arrival": {
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:35:51.002000Z"
            }
          },
          "geofence": {
            "geometry": {
              "type": "Point",
              "coordinates": [-122.3996, 37.7939]
            },
            "geofence_id": "7159040c-ad03-4a49-9c1f-11f9763cdf9b",
            "radius": 30,
            "metadata": {
              "stop_id": 2937
            }
          },
          "route_to": {
            "duration": 120,
            "distance": 600,
            "start_location": {
              "geometry": {
                 "type": "Point",
                 "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:33:51.002000Z"
            }
          },
          "exit": {
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:36:51.002000Z"
            }
          },
          "duration": 60
        }
      },
      {
        "type": "device_status",
        "data": {
          "value": "inactive",
          "start": {
            "recorded_at": "2019-09-13T19:40:51.002000Z",
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:39:51.002000Z"
            }
          },
          "end": {
            "recorded_at": "2019-09-13T20:40:51.002000Z",
            "location": {
              "geometry": {
                "type": "Point",
                "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T20:40:52.002000Z"
            }
          },
          "reason": "outage.software"
        }
      },
      {
        "type": "trip_marker",
        "data": {
          "recorded_at": "2019-09-13T20:40:52.002000Z",
          "location": {
            "coordinates": [-122.3996, 37.7939],
            "type": "Point"
          },
          "metadata": {
            "id": "1235"
          },
          "route_to": {
            "duration": 2654,
            "distance": 377,
            "start_location": {
              "geometry": {
                 "type": "Point",
                 "coordinates": [-122.3996, 37.7939]
              },
              "recorded_at": "2019-09-13T19:33:51.002000Z"
            }
          }
        }
      }
    ]
  }
}
Name Type Description
summary.locations object Object representing the location time series of the full trip. Follows GeoJSON geometry of type LineString
summary.locations.type string As of right now, only LineString is supported
summary.locations.coordinates array Array of coordinates arrays; each item follows [longitude, latitude, elevation, timestamp]; elevation can be null
summary.distance int Distance for entire trip, in meters
summary.duration int Duration for entire trip, in seconds
summary.started_at string ISO 8601 date when the trip started
summary.completed_at string ISO 8601 date when the trip was completed
summary.device_id string Unique identifier of the device associated with the trip, case sensitive
summary.markers array Array of markers
summary.markers[].type string Marker type; can be one of device_status, geofence or trip_marker
summary.markers[].data object Marker data; dependent on marker type

Detailed description of device_status markers:

Name Type Description
end object End of the device status segment
end.location object Location object when the device_status changed
end.location.geometry object GeoJSON geometry of type Point
end.location.geometry.type string As of right now, only Point is supported
end.location.geometry.coordinates array Array of longitude and latitude
end.location.recorded_at string ISO 8601 date when the location was recorded
end.recorded_at string ISO 8601 date when the device status change was recorded
start object Start of the device status segment
start.location object Location object when the device_status changed
start.location.geometry object GeoJSON geometry of type Point
start.location.geometry.type string As of right now, only Point is supported
start.location.geometry.coordinates array Array of longitude and latitude
start.location.recorded_at string ISO 8601 date when the location was recorded
start.recorded_at string ISO 8601 date when the device status change was recorded
value string Device status. Can be one of active, inactive or disconnected

Detailed description of geofence markers:

Name Type Description
arrival object Object representing details about the geofence arrival
arrival.location object Location object that triggered geofence arrival
arrival.location.geometry object GeoJSON geometry of type Point
arrival.location.geometry.type string As of right now, only Point is supported
arrival.location.geometry.coordinates array Array of longitude and latitude
arrival.location.recorded_at string ISO 8601 date when the location was recorded
duration int Duration of time spent inside geofence, in seconds
exit object Object representing details about the geofence exit
exit.location object Location object that triggered geofence exit
exit.location.geometry object GeoJSON geometry of type Point
exit.location.geometry.type string As of right now, only Point is supported
exit.location.geometry.coordinates array Array of longitude and latitude
exit.location.recorded_at string ISO 8601 date when the location was recorded
geofence object Object representing the defined geofence
geofences.geometry object GeoJSON geometry of type Point
geofences.geometry.type string As of right now, only Point is supported
geofences.geometry.coordinates array Array of longitude and latitude
geofences.radius int Defines the radius (in meters) of a circular geofence (optional, default is 30)
geofences.metadata object Any metadata you want to assign to this geofence (optional)
geofence object Object representing the defined geofence
route_to object Object giving details about the route taken to this geofence
route_to.distance int Distance traveled from previous geofence (or fist location), in meter
route_to.duration int Duration traveled from previous geofence (or fist location), in seconds
route_to.start_location object Location object where route_to calculation is based on. Starting point of route to this geofence.
route_to.start_location.geometry object GeoJSON geometry of type Point of start location
route_to.start_location.geometry.type string As of right now, only Point is supported
route_to.start_location.geometry.coordinates array Array of longitude and latitude
route_to.start_location.recorded_at array ISO 8601 date when the start location was recorded

Detailed description of trip_marker markers:

Name Type Description
location object Location object where the trip marker was created
location.geometry object GeoJSON geometry of type Point
location.geometry.type string As of right now, only Point is supported
location.location.geometry.coordinates array Array of longitude and latitude
metadata object Any metadata assigned to this trip marker
recorded_at string ISO 8601 date when trip marker was recorded
route_to object Object giving details about the route taken to this trip marker
route_to.distance int Distance traveled from previous trip marker (or fist location), in meter
route_to.duration int Duration traveled from previous trip marker (or fist location), in seconds
route_to.start_location object Location object where route_to calculation is based on. Starting point of route to this trip marker.
route_to.start_location.geometry object GeoJSON geometry of type Point of start location
route_to.start_location.geometry.type string As of right now, only Point is supported
route_to.start_location.geometry.coordinates array Array of longitude and latitude
route_to.start_location.recorded_at array ISO 8601 date when the start location was recorded

POST /trips/{trip_id}/complete

Run in PostmanPOST https://v3.api.hypertrack.com/trips/{trip_id}/complete

curl -X POST \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}/complete
const request = require("request");

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/trips/{trip_id}/complete",
  auth: {
    user: "{AccountId}",
    password: "{SecretKey}"
  }
};

request(options, (err, res, body) => {
  console.dir(err, res, body);
});
import requests

response = requests.request("POST", "https://v3.api.hypertrack.com/trips/{trip_id}/complete", auth=("{AccountId}", "{SecretKey}"))

print(response.text)
OkHttpClient client = new OkHttpClient();

String authString = "Basic " +
  Base64.getEncoder().encodeToString(
    String.format("%s:%s", "4IZ7fWXxRmmxFL4RWcAgxrPWBD8","rXc40pSVlYkhJsNkcQCncp-c5CVxQeRi6s6bAWXM6T76bWwUlaUMlQ")
      .getBytes()
  );

Request request = new Request.Builder()
  .url("https://v3.api.hypertrack.com/trips/{trip_id}/complete")
  .post()
  .addHeader("Authorization", authString)
  .build();

Response response = client.newCall(request).execute();

System.out.println(response.body().string());
<?php

$request = new HttpRequest();
$request->setUrl('https://v3.api.hypertrack.com/trips/{trip_id}/complete');
$request->setMethod(HTTP_METH_POST);

$basicAuth = "Basic " . base64_encode('{AccountId}' . ':' . '{SecretKey}');

$request->setHeaders(array(
  'Authorization' => $basicAuth
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

?>
require 'uri'
require 'net/http'
require 'base64'

url = URI("https://v3.api.hypertrack.com/trips/{trip_id}/complete")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic ' + Base64.strict_encode64( '{AccountId}' + ':' + '{SecretKey}' ).chomp

response = http.request(request)
puts response.read_body
import Foundation

let base64encoded = "{AccountId}:{SecretKey}".data(using: .isoLatin1)?.base64EncodedString() ?? ""

let headers = [
  "Authorization": "Basic \(base64encoded)",
]

let request = NSMutableURLRequest(url: NSURL(string: "https://v3.api.hypertrack.com/trips/{trip_id}/complete")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"Authorization": [NSString stringWithFormat:@"Basic %@",
                           [ASIHTTPRequest base64forData:
                            [[NSString stringWithFormat:@"%@:%@", @"{AccountId}", @"{SecretKey}"]
                             dataUsingEncoding:NSUTF8StringEncoding]]]};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://v3.api.hypertrack.com/trips/{trip_id}/complete"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Complete an active trip. This will initiate a procedure on the HyperTrack platform.

The request will start the procedure and confirm a pending completion with a trips webhook. Until the completion is done, the trip will have the status processing_completion.

Authentication: Basic Auth

HTTP 202 - Trip completion initiated

{
  "message": "pending completion for trip '00112233-4455-6677-8899-AABBCCDDEEFF'"
}

Path Parameters

trip_id - a string representing the ID of a trip, case sensitive

Completion finished

As soon as the trip was completed on HyperTrack systems, it will be extended with a summary property.

Completed trips do not have an estimate property because routing was completed.

HTTP 200 - Completed trip payload

{
  "trip_id": "aabb2233-8899-4455-3210-aabbccddeeff",
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "started_at": "2019-05-03T06:25:51.238000Z",
  "completed_at": "2019-05-03T06:25:51.238000Z",
  "status": "completed",
  "views": {
    "embed_url": "https://embed.hypertrack.com/dkdkddnd",
    "share_url": "https://trck.at/abcdef"
  },
  "metadata": {
    "customer_id": "ABC123"
  },
  "destination": {
    "geometry": {
      "type": "Point",
      "coordinates": [
        -122.3980960195712,
        37.7930386903944
      ]
    },
    "radius": 30,
    "scheduled_at": "2019-05-03T06:25:51.238000Z",
    "arrived_at": "2019-05-03T06:25:51.238000Z"
  },
  "summary": {
     ...
  }
}

Response Attributes

Name Type Description
trip_id string Unique identifier of the newly created trip, case sensitive
device_id string Unique identifier of the device associated with the trip, case sensitive
started_at string Timestamp for trip starting time
completed_at string Timestamp of trip completion time (only set when trip is completed), can be null
status string Trip status, can be active, completed or processing_completion
views.embed_url string Embeddable trip view
views.share_url string Shareable trip view
destination object Defined trip destination
destination.geometry object GeoJSON geometry of type Point for destination point
destination.radius int Radius (in meters) of a circular trip destination
destination.scheduled_at string Timestamp for scheduled arrival
destination.arrived_at string Timestamp first enter to destination
destination.exited_at string Timestamp first exit from destination
geofences array Array of geofence objects (optional)
geofences[].geometry object GeoJSON geometry of type Point
geofences[].geometry.type string As of right now, only Point is supported
geofences[].geometry.coordinates array Array of longitude and latitude
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30)
geofences[].metadata object Any metadata you want to assign to this geofence (optional)
geofences[].arrived_at string Timestamp first enter to geofence
geofences[].exited_at string Timestamp first exit from geofence
summary object Trip summary
metadata object Metadata provided at trip creation

Webhooks

Webhooks let you subscribe to a real-time stream of location, and trip status data generated by HyperTrack. Rather than making an API call, HyperTrack can send an HTTPS request to an endpoint that you specify. Events are published for all devices associated with the account.

Webhook Payload

The overall POST payload has a static structure. The type of the webhook indicates the structure of the data object.

[{
  "created_at": "2019-02-27T22:50:29.000000Z",
  "data": { ... },
  "location": { ... },
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "recorded_at": "2019-02-27T22:50:24.000000Z",
  "type": "",
  "version": "2.0.0"
}]
Name Type Description
device_id string Unique device identifier, case sensitive
created_at string ISO 8601 date and time when webhook was sent (server timestamp)
recorded_at string ISO 8601 date and time when event was recorded (client timestamp). Not available for trip webhooks (e.g. creation and completion)
type string Type of webhook data. Could be either location, device_status, battery or trip
data object Either location, device_status, battery or trip data, see details below.
location object GeoJSON object with type and coordinates. Provided as context to trip delay webhooks only
version string Version string of the webhook. Current version is "2.0.0"

Location Payload

{
    "created_at": "2019-07-01T20:00:01.247377Z",
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "recorded_at": "2019-07-01T20:00:00.000000Z",
    "type": "location",
    "data": {
        "accuracy": 9.64,
        "geometry": {
            "type": "Point",
            "coordinates": [
                -6.2755,
                57.6398983
                124
            ]
        },
        "speed": 0.0,
        "bearing": 313.94
    },
    "version": "2.0.0"
}
Name Type Description
data.geometry object Location in GeoJSON format
data.geometry.type string As of right now, only Point is supported
data.geometry.coordinates array Array of longitude, latitude and (optional) altitude (in m)
data.accuracy float (optional) accuracy in m
data.bearing float (optional) bearing in degrees starting at due north and continuing clockwise around the compass
data.speed float (optional) speed in m/s

Device Status Payload

{
    "created_at": "2019-07-01T20:00:01.247377Z",
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "recorded_at": "2019-07-01T20:00:00.000000Z",
    "type": "device_status",
    "data": {
        "value": "active",
        "activity": "walk"
    },
    "location": {
        "type": "Point",
        "coordinates": [
                -6.2755,
                57.6398983
                124
            ]
    },
    "version": "2.0.0"
}
Name Type Description
data.value string Device status. One of active, inactive or disconnected
data.activity string For active devices only, can be one walk, run, drive, cycle, stop, moving
data.reason string For inactive devices only. Can be one of location_permissions_denied/motion_activity_permissions_denied (user denied location/activity permissions), location_services_disabled/motion_activity_services_disabled (user disabled location/activity services), motion_activity_services_unavailable (activity services not available on device), stopped_programmatically (tracking was stopped programmatically from host application) or unknown
location object Location in GeoJSON format
location.type string As of right now, only Point is supported
location.coordinates array Array of longitude latitude and (optional) altitude (in m)

Battery Payload

{
    "created_at": "2019-07-01T20:00:01.247377Z",
    "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
    "recorded_at": "2019-07-01T20:00:00.000000Z",
    "type": "battery",
    "data": {
        "value": "low"
    },
    "location": {
        "type": "Point",
        "coordinates": [
                -6.2755,
                57.6398983
                124
            ]
    },
    "version": "2.0.0"
}
Name Type Description
data.value string Battery status. Values include low, normal and charging
location object Location in GeoJSON format
location.type string As of right now, only Point is supported
location.coordinates array Array of longitude latitude and (optional) altitude (in m)

Trip Payload

{
  "created_at": "2019-07-01T14:00:00.000000Z",
  "data": {
    "value": "created",
    "trip_id": "123E4567-E89B-12D3-A456-426655440000",
    "trip_metadata": { "customer": "1234" }
  },
  "device_id": "00112233-4455-6677-8899-AABBCCDDEEFF",
  "type": "trip",
  "version": "2.0.0"
}

If you create trips, you will receive trip events whenever ...

Name Type Description
data.value string One of: created, destination_arrival, destination_exit, geofence_enter, geofence_exit, delayed or completed
data.trip_id string Unique identifier of the trip, case sensitive
data.trip_metadata Object Metadata that you have assigned to this trip (optional)
data.geofence_metadata Object Metadata that you have assigned to the corresponding geofence, only available if value is geofence_enter or geofence_exit
data.arrive_at string Timestamp with new arrived date, only available if value is delayed

SDKs

Android

This reference shows methods available in the Android SDK. You can also review the generated JavaDoc files.

Initialize

Initialize the SDK with your activity and publishable key only.

If you don't want SDK to start tracking and/or request data access permissions immediately, you can use one of overloaded initialize variants and set startTracking or stopTracking to control the tracking status.

HyperTrack.initialize(MyActivity.this, 'your-publishable-key-here');
Parameter Type Description
activity Activity Will be used to add permission request fragment (if required) and to access application's Context
publishableKey String Your publishable key from the dashboard

Initialize with handler

Initialize the SDK with your activity, publishable key, and a handler.

If you don't want SDK to start tracking and/or request data access permissions immediately, you can use one of overloaded initialize variants and then use pair startTracking(boolean, TrackingInitDelegate) stopTracking() to control tracking status.

class myInitDelegate implements TrackingInitDelegate {
    public void onSuccess() {
        // invoked on successful result
    }

    public void onError(TrackingInitError error) {
        // invoked only in case of failure
    }
}

...

HyperTrack.initialize(MyActivity.this, "your-publishable-key-here", myInitDelegate);
Parameter Type Description
activity Activity Will be used to add permission request fragment (if required) and to access application's Context
publishableKey String Your publishable key from the dashboard
trackingInitDelegate TrackingInitDelegate Handler for initialization result

Initialize with handler and config

Initialize the SDK with your activity, publishable key, custom configuration, and a handler.

// define the handler
class myInitDelegate implements TrackingInitDelegate {
    public void onSuccess() {
        // invoked on successful result
    }

    public void onError(TrackingInitError error) {
        // invoked only in case of failure
    }
}

...

// initialize the SDK without a handler and disable tracking.
HyperTrack.initialize(MyActivity.this, "your-publishable-key-here", false, false, null);

...

// enable tracking later and pass in new handler.
HyperTrack.startTracking(true, myInitDelegate);
Parameter Type Description
activity Activity Will be used to add permission request fragment (if required) and to access application's Context
publishableKey String Your publishable key from the dashboard
shouldStartTracking boolean Start tracking automatically after initialization
shouldRequestPermissionIfMissing boolean Present permission request dialog if permissions are missing
trackingInitDelegate TrackingInitDelegate Handler for initialization result

Start tracking

Start tracking. Only required if SDK was initialized without tracking or tracking was stopped before.

class myInitDelegate implements TrackingInitDelegate {
    public void onSuccess() {
        // invoked on successful result
    }

    public void onError(TrackingInitError error) {
        // invoked only in case of failure
    }
}

HyperTrack.startTracking(true, myInitDelegate);
Parameter Type Description
shouldRequestPermissionIfMissing boolean Present permission request dialog (if needed)
delegate TrackingInitDelegate Handler for initialization result (optional)

Stop tracking

Stop tracking.

HyperTrack.stopTracking();

Check tracking status

Check tracking status.

HyperTrack.isTracking();

Get device ID

Obtain device identifier. Returns an empty string if SDK was not yet initialized.

String deviceID = HyperTrack.getDeviceId();

Set name and metadata

Set name and metadata for device tracking data.

// create new metadata map
Map<String,Object> myMetadata = new HashMap<>();

// add external id to metadata
myMetadata.put('external-id', 'your-external-id');

HyperTrack.setNameAndMetadataForDevice('your-custom-device-name', myMetadata);
Parameter Type Description
name String Custom device name (optional)
metaData Map Custom metadata as key-value pair (optional)

Create trip marker

Create a trip marker with configurable payload. Please, bear in mind that this will be serialized as JSON.

// create new marker payload
Map<String,Object> payload = new HashMap<>();

// add event details
payload.put("item", "Martin D-18");
payload.put("previousOwners", Collections.emptyList());
payload.put("price", 7.75);

HyperTrack.tripMarker(payload);
Parameter Type Description
payload Map Trip marker data as key-value pair

Customize notification

HyperTrack tracking runs as a separate foreground service. When tracking is activated, users will see a persistent notification. By default, it displays the app icon with text {app name} is running. You can customize the notification appearance.

HyperTrack.addNotificationIconsAndTitle(
    R.drawable.ic_small,
    R.drawable.ic_large,
    notificationTitleText,
    notificationBodyText
);
Parameter Type Description
smallIconId int Small icon ID
largeIconId int Large icon ID
title String Title (optional). Set to null to keep the default title
body String Body (optional). Set to null to keep the default body

iOS

This reference shows methods available in the iOS SDK. This reference is split into Swift and Objective C. Please select the appropriate language in the top right panel.

Initialize

Initialize the SDK with your publishable key only.

If you don't want SDK to start tracking and/or request data access permissions immediately, you can use one of overloaded initialize variants and set startTracking or stopTracking to control the tracking status.

HyperTrack.initialize(publishableKey: "<#Paste your Publishable Key here#>")
[HTSDK initializeWithPublishableKey: @"<#Paste your Publishable Key here#>"];
Parameter Type Description
publishableKey String Your publishable key from the dashboard

Initialize with handler and config

Initialize the SDK with your publishable key, custom configuration, and a handler.

// define an error handler
extension AppDelegate: HyperTrackDelegate {
  func hyperTrack(_ hyperTrack: AnyClass, didEncounterCriticalError criticalError: HyperTrackCriticalError) {
    /// Handle errors here
  }
}

...

// initialize the SDK and disable tracking
HyperTrack.initialize(
    publishableKey: "<#Paste your Publishable Key here#>",
    delegate: self,
    startsTracking: false,
    requestsPermissions: false)

...

// enable tracking later
HyperTrack.startTracking(requestsPermissions: true)
// define an error handler
@interface AppDelegate () <HTSDKDelegate>
@end

@implementation AppDelegate

- (void)hyperTrack:(Class)hyperTrack didEncounterCriticalError:(HTSDKCriticalError *)criticalError {
    /// Handle errors here
}

@end

...

// initialize the SDK and disable tracking
[HTSDK initializeWithPublishableKey:@"<#Paste your Publishable Key here#>"
                           delegate:self
                     startsTracking:false
                requestsPermissions:false];

...

// enable tracking later
[HTSDK startTrackingWithRequestsPermissions:true];
Parameter Type Description
publishableKey String Your publishable key from the dashboard
startsTracking boolean Start tracking automatically after initialization (optional in Swift, true by default)
requestsPermissions boolean Request Location and Motion permissions on your behalf (optional in Swift, true by default)
delegate Handler Error handler for initialization (optional in Swift, nil by default)

The delegate method is called if the SDK encounters a critical error that prevents it from running. This includes:

Start tracking

Start tracking. Only required if SDK was initialized without tracking or tracking was stopped before.

HyperTrack.startTracking(requestsPermissions: true)
[HTSDK startTrackingAndRequestPermissions:YES];
Parameter Type Description
requestsPermissions boolean Request Location and Motion permissions on your behalf (optional in Swift, true by default)

Stop tracking

Stop tracking.

HyperTrack.stopTracking()
[HTSDK stopTracking];

Check tracking status

Check tracking status.

HyperTrack.isTracking
[HTSDK isTracking]

Get device ID

Obtain SDK-generated device identifier.

HyperTrack.deviceID
[HTSDK deviceID]

Set name and metadata

Set name and metadata for device tracking data.

HyperTrack.setDevice(name: "Device name", andMetadata: nil) { (error) in
    /// Handle errors here
}
[HTSDK setDeviceWithName:@"Device name"
        metadata:nil
        completionHandler:^(HTSDKDeviceNameError * _Nullable error) {
            /// Handle errors here
       }];
Parameter Type Description
name String Custom device name (optional)
metadata Dictionary (String) Custom metadata as string dictionary (optional)
completionHandler Handler Error handler (optional)

Create trip marker

Create a trip marker with configurable payload. Please, bear in mind that this will be converted to JSON from a Dictionary type.

HyperTrack.setTripMarker(["custom keys": "custom values"]) { (error) in
    /// Handle errors here
}
[HTSDK setTripMarker:@{ @"custom keys": @"custom values" }
   completionHandler:^(HTSDKCustomEventError * _Nullable error) {
       /// Handle errors here
   }];
Parameter Type Description
metadata Dictionary (String) Trip marker data as a dictionary
completionHandler Handler Error handler (optional)

Views

Android

Android Views are implemented using GraphQL subscriptions and enable server-to-client communication without the need to integrate Webhooks on the backend.

The module handles websockets and provides easy-to-consume methods to retrieve device status and subscribe to programmatic notifications about key moments in the movement tracking of devices and trips, as they happen.

Get device status

// Get SDK instance with Context reference
// replace <PUBLISHABLE_KEY> with your own key
HyperTrackViews hypertrackView = HyperTrackViews.getInstance(this, <PUBLISHABLE_KEY>);

// replace <DEVICE_ID> with your device ID
hypertrackView.getDeviceMovementStatus(<DEVICE_ID>,
    new Consumer<MovementStatus>() {
        @Override
        public void accept(MovementStatus movementStatus) {
            Log.d(TAG, "Got movement status data " + movementStatus);
        }
    });
val hyperTrackView = HyperTrackViews.getInstance(this, PUBLISHABLE_KEY)
        hyperTrackView.getDeviceMovementStatus(DEVICE_ID)
        {Log.d(TAG, "Got movement status $it")}

Get device information by device ID. The callback receives a MovementStatus object describing the device.

Movement Status

The device movement status object encapsulates all data associated with a device, similar to the Device API. It provides the latest snapshot of the device state, including ...

Location Object
Location location = movementStatus.location;
if (location != null) {
  Log.d(TAG, "Got device location " + location +
  " with latitude " + location.getLatitude() +
  " and longitude " + location.getLongitude());
}
val location = movementStatus?.location
location?.let {
  Log.d(TAG, "Got device location $location " +
          "with latitude ${location.latitude}" +
          "and longitude ${location.longitude}")
Accessor method Type Description
getLatitude() double Latitude in degrees. Negatives are for southern hemisphere.
getLongitude() double Longitude in degrees. Negatives are for western hemisphere.
getAltitude() Double Altitude in m. Could be null, if value is not available.
getSpeed() Double Speed in m/s. Could be null, if device is stationary
getBearing() Double Bearing in degrees starting at due north and continuing clockwise around the compass
getAccuracy() Double Horizontal accuracy in m
getRecordedAt() String ISO 8601 date when the location was recorded
Device Status Object
DeviceStatus status = movementStatus.deviceStatus;
if (status != null) {
  Log.d(TAG, "Device is " + (status.isDisconnected() ? "disconnected" : "connected"));
}
val status = movementStatus?.deviceStatus
status?.let {
    Log.d(TAG, "Device is ${(if (status.isDisconnected) "disconnected"  else "connected")}")
}
Member Type Description
createdAt String ISO 8601 date when the device status was created
isActive() boolean Returns true if device is active (it's current location is known and updated) and false otherwise
isDisconnected() boolean Returns true if device is disconnected (it's location wasn't updated for a while) and false otherwise
isInactive() boolean Returns true if tracking data is unavailable because of lack of permissions or tracking was stopped intentionally and false otherwise
status int Property provides more extended description of current state, e.g. whether it it is driving, if active, etc. See JavaDoc for the list of possible values and their meaning.
Device Info Properties
DeviceInfo deviceInfo = movementStatus.deviceInfo;
if (deviceInfo != null) {
    Log.d(TAG, "Got status for device " + deviceInfo.name);
}
val deviceInfo = movementStatus?.deviceInfo
deviceInfo?.let {
    Log.d(TAG, "Status from device ${deviceInfo.name}")
}
Parameter Type Description
appName String Name of the hosting app
appVersionNumber String Version of the hosting app
appVersionString String Version of the hosting app
deviceBrand String The device brand
deviceModel String The device model
name String The name of the device
osName String The operating system of the device, can be one of iOS or Android
osVersion String The version of the operating system on the device
sdkVersion String The HyperTrack SDK version on the device. Can be reviewed here: Android, iOS, React Native
DeviceViewUrls Properties

This object incapsulates resources that could be used to open WebView Widget (embedded view) or for sharing location via link.

    String shareUrl = movementStatus.deviceViewUrls.embedUrl;
    Uri uri = Uri.parse(shareUrl + PUBLISHABLE_KEY);
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
    val shareUrl = movementStatus.deviceViewUrls.embedUrl
    val uri = Uri.parse(shareUrl!! + PUBLISHABLE_KEY)
    val intent = Intent(Intent.ACTION_VIEW, uri)
    if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
Parameter Type Description
embedUrl String Embeddable view URL
shareUrl String Sharable view URL
Trip Properties
Trip{
    tripId="3737e382-b251-11e9-a7f6-f6b591671d93",
    startedAt="2019-07-29T22:35:49.963554Z",
    completedAt="",
    status="active",
    destination=Destination{
        geometry=Geometry{
            coordinates=[-122.437941, 37.800563]
        },
        radius=30,
        scheduledAt=""
    },
    estimate=Estimate{ ... },
    metadata="",
    summary=""
}
Method Type Description
getTripId() String Unique identifier of the newly created trip, case sensitive
getStatus() String Trip status, can be either active or completed
getStartedAt() String Timestamp for trip starting time
getMetadata() String Metadata provided at trip creation
getSummary() String Trip summary, only provided upon completion of a trip
getDestination() Trip.Destination Destination of the trip, or null if trip has no destination
getEstimate() Trip.Estimate Trip summary, only provided for trips with status active
getCompletedAt() String ISO 8601 date when the trips was completed or null if it haven't been completed
Trip Estimate Properties
Estimate{
    arriveAt="",
    reroutesExceeded=false,
    route=Route{ ... }
}
Method Type Description
getArriveAt() String Timestamp for estimated arrival
isRerouteExceeded() Boolean Indicates if re-route limit of 10 was exceeded
getRoute() Trip.Route Planned route segments to destination
Trip Route Properties
Route{
    distance=210,
    duration=1720,
    startAddress="1 Embarcadero Center, San Francisco, CA, 94122",
    endAddress="353 Sacramento St, San Francisco, CA, 94122",
    polyline=Polyline{ ... }
}
Method Type Description
getDistance() Integer Timestamp for estimated arrival
getDuration() Integer Indicates if re-route limit of 10 was exceeded
getStartAddress() String Street address lookup for segment start
getEndAddress() String Street address lookup for segment end
getPoints() List of List of Double Planned route segments to destination, as array of longitude, latitude and altitude (optional) tuples
Trip Destination Properties
Destination{
    geometry=Geometry{ ... },
    radius=30,
    scheduledAt="2019-07-29T22:35:49.963554Z"
}
Method Type Description
getLatitude() Double Latitude coordinate of destination center point in degrees. Negatives are for southern hemisphere
getLongitude() Double Longitude coordinate of destination center point in degrees. Negatives are for western hemisphere
getRadius() Integer Radius (in meters) of a circular trip destination
getScheduledAt() String Timestamp for scheduled arrival

Subscribe to updates

// Get SDK instance with Context reference
// replace <PUBLISHABLE_KEY> with your own key
HyperTrackViews hypertrackView = HyperTrackViews.getInstance(this, <PUBLISHABLE_KEY>);

// replace <DEVICE_ID> with your device ID
hypertrackView.subscribeToDeviceUpdates(<DEVICE_ID>,
   new DeviceUpdatesHandler() {
       @Override
       public void onLocationUpdateReceived(@NonNull Location location) {
           Log.d(TAG, "onLocationUpdateReceived: " + location);
       }

       @Override
       public void onBatteryStateUpdateReceived(@BatteryState int i) {
           Log.d(TAG, "onBatteryStateUpdateReceived: " + i);
       }

       @Override
       public void onStatusUpdateReceived(@NonNull StatusUpdate statusUpdate) {
           Log.d(TAG, "onStatusUpdateReceived: " + statusUpdate);
       }

       @Override
       public void onTripUpdateReceived(@NonNull Trip trip) {
           Log.d(TAG, "onTripUpdateReceived: " + trip);
       }

       @Override
       public void onError(Exception e, String deviceId) {
           Log.w(TAG, "onError: ", e);
       }

       @Override
       public void onCompleted(String deviceId) {
           Log.d(TAG, "onCompleted: " + deviceId);
       }
   }
);

You can subscribe to receive device state changes as they come in. The DeviceUpdatesHandler should implement and override the following interface methods:

Method Parameter Description
onLocationUpdateReceived Location Location update
onBatteryStateUpdateReceived BatteryState Battery update, can be one of BATTERY_CHARGING, BATTERY_LOW, and BATTERY_NORMAL
onStatusUpdateReceived StatusUpdate Status update
onTripUpdateReceived Trip Trip update
onError Exception, Device ID (String) Error with exception details and device ID
onCompleted Device ID (String) Completion with Device ID

StatusUpdate Properties

StatusUpdate{
    value="WALK",
    hint="",
    recordedAt="2019-07-29T22:35:49.963554Z"
}
Parameter Type Description
value String Health event type, can be one of CYCLE, DRIVE, MOVING, RUN, STOP, or WALK
hint String Health hint. Additional information about the health event
recordedAt String ISO 8601 date when the device status was recorded

Unsubscribe from updates

hypertrackView.stopAllUpdates();

You can stop receiving updates you are subscribed to.

GeoJSON

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [125.6, 10.1, 123]
  },
  "properties": {
    "name": "Dinagat Islands"
  }
}

The GeoJSON format adopted by HyperTrack is based on the RFC 7946 specification. It is used as a generalized construct to encode geographic data structures using a JSON format. It supports a variety of types, with Point being the most commonly used.

Device status and activity

HyperTrack currently supports the following status and activity types:

Icon Type Description Device connected Movement tracked Activity identified
disconnected icon Disconnected We lost connection with the device unexpectedly (no data received for over an hour)
inactive icon Inactive The device is not trackable for known reasons Yes
unknown icon Unknown The device is moving, activity is unknown Yes Yes
stop icon Stop The device is stationary Yes Yes Yes
walk icon Walk The device is on a walking person Yes Yes Yes
run icon Run The device is on a running person Yes Yes Yes
ride icon Cycle The device is in a bicycle Yes Yes Yes
drive icon Drive The device is in a car Yes Yes Yes

Activity types are provided by the mobile OS using a combination of sensory data on the device combined with machine learning to accurately predict the activity in real-time. For more details, please see the OS references (iOS and Android).

HTTP Errors

We are adopting the RFC 7807 standard for our error messages.

{
  "status": 404,
  "code": "trip_not_found",
  "title": "Trip could not be found",
  "type": "https://docs.hypertrack.com/#trips-api-trip-not-found",
  "detail": "Trip with the id '00112233-4455-6677-8899-AABBCCDDEEFF' does not exist"
}

The standard requires at least the type property. Everything else is optional. For HyperTrack, we always send title, detail, status, and code in addition. To detail out some errors (for instance multiple invalid fields), the append additional properties as documented in the respective error section.

Parameter Type Description
status Number HTTP status code
code String Error class code
title String Brief summary of the error class
type URL URL to the respective error page (about:blank if none is provided)
detail String Detailed description of the error instance
invalid_params Object A list of invalid parameters to review (options)

Trips API

The Trips API can return one of the following errors. Please review the reference carefully to understand the error reasons and potential steps to overcome the issues faced.

Unauthorized

{
  "message": "Unauthorized"
}

HTTP 401 (Unauthorized)

Potential reason: The Authorization header in the request is invalid or missing.

Potential actions:

Wrong content-type

{
  "status": 400,
  "code": "wrong_content_format",
  "title": "Wrong content format",
  "type": "https://docs.hypertrack.com/#trips-api-wrong-content-type",
  "detail": "The content submitted in the request body is not in valid JSON format"
}

Potential reasons:

Potential actions: Please double check that the body you generate for the request is in valid JSON format. You can use this small tool to ensure your JSON is valid.

Trip not found

{
  "status": 404,
  "code": "trip_not_found",
  "title": "Trip could not be found",
  "type": "https://docs.hypertrack.com/#trips-api-trip-not-found",
  "detail": "Trip with the id '00112233-4455-6677-8899-AABBCCDDEEFF' does not exist"
}

Potential reasons:

Potential actions: Ensure that the right ID is used - with uppercase letters and no changes to the format(e.g. don't escape the -).

Device not found

{
  "status": 400,
  "code": "device_not_found",
  "title": "Device could not be found",
  "type": "https://docs.hypertrack.com/#trips-api-device-not-found",
  "detail": "Device with the id '00112233-4455-6677-8899-AABBCCDDEEFF' does not exist"
}

Potential reasons:

Potential actions:

Route not found

{
  "status": 400,
  "code": "route_not_found",
  "title": "Route could not be found",
  "type": "https://docs.hypertrack.com/#trips-api-route-not-found",
  "detail": "Could not generate a route from the device location to the set destination"
}

Potential reasons:

Potential actions:

Validation error

{
  "status": 400,
  "code": "validation_error",
  "title": "Trip request is malformed",
  "type": "https://docs.hypertrack.com/#trips-api-validation-error",
  "detail": "The request format does not have the correct format. Please review the invalid parameters",
  "invalid_params": [
    {
      "name": "destination.geometry.type",
      "reason": "Only supported type is 'Point'. Received 'Polygon' instead"
    }
  ]
}

Potential reasons:

Potential actions: Please review and fix the invalid parameters in invalid_params. You can also use this small tool to ensure your request body complies with our JSON schema for the API call.

Completion not possible

{
  "status": 400,
  "code": "completion_not_possible",
  "title": "Trip cannot be completed",
  "type": "https://docs.hypertrack.com/#trips-api-completion-not-possible",
  "detail": "Trip with the id '00112233-4455-6677-8899-AABBCCDDEEFF' cannot be completed"
}

Potential reasons:

Potential actions:

Unauthorized

// HTTP Status: 401
{
  "message": "Unauthorized"
}

Potential reasons:

Potential actions:

Route creation failed

{
  "status": 500,
  "code": "route_error",
  "title": "Failed to generate the route",
  "type": "https://docs.hypertrack.com/#trips-api-route-creation-failed",
  "detail": "Server could not complete the route generation"
}

Potential reasons:

Potential actions:

Devices API

The Devices API can return one of the following errors. Please review the reference carefully to understand the error reasons and potential steps to overcome the issues faced.

Unauthorized

{
  "message": "Unauthorized"
}

HTTP 401 (Unauthorized)

Potential reason: The Authorization header in the request is invalid or missing.

Potential actions:

Device not found

{
  "status": 404,
  "code": "device_not_found",
  "title": "Device could not be found",
  "type": "https://docs.hypertrack.com/#devices-api-trip-not-found",
  "detail": "Device with the id '00112233-4455-6677-8899-AABBCCDDEEFF' does not exist"
}

HTTP 404 (Not Found)

Potential reasons:

Potential actions:

Method Not Allowed

{
  "status": 405,
  "code": "method_not_allowed",
  "title": "Method Not Allowed",
  "type": "https://docs.hypertrack.com/#devices-api-method-not-allowed"
}

HTTP 405 (Method Not Allowed)

Potential reasons:

Potential actions:

Validation Error

{
  "status": 400,
  "code": "validation_error",
  "title": "Device request is malformed",
  "detail": "The request format does not have the correct format. Please review the invalid parameters",
  "validation_errors": [
    {
      "field": "name",
      "message": "Name cannot be empty."
    }
  ],
  "type": "https://docs.hypertrack.com/#devices-api-validation-error"
}

HTTP 400 (Bad Request)

Potential reasons:

Potential actions:

Properties Cannot Be Patched

{
  "status": 400,
  "code": "cannot_patch_property",
  "title": "Properties cannot be patched",
  "detail": "The property {x} is immutable. You can only patch: name and metadata",
  "type": "https://docs.hypertrack.com/#devices-api-properties-cannot-be-patched"
}

HTTP 400 (Bad Request)

Potential reasons:

Potential actions:

Wrong content-type

{
  "status": 400,
  "code": "wrong_content_format",
  "title": "Wrong content format",
  "type": "https://docs.hypertrack.com/#devices-api-wrong-content-type",
  "detail": "The content submitted in the request body is not in valid JSON format"
}

Potential reasons:

Potential actions: Please double check that the body you generate for the request is in valid JSON format. You can use this small tool to ensure your JSON is valid.

FAQ

We compiled a list of frequently asked technical questions below. If you these do not answer your questions, please send us an email and we will get back to you as soon as possible.

We currently support Android (API version 19+, starting with Android 4.4 Kit Kat) and iOS (version 10+) devices through native SDKs. All devices need to have GPS modules to be supported.

The Quickstart app is completely open sourced with the MIT License. It is there for you to reduce the time it takes to build your own app. We are actively adding more open sourced apps built with HyperTrack that you can fork and re-purpose for your own needs.

We’re planning to release hybrid SDKs to support these apps. Please cast your vote on our feature request board to help us prioritize effectively.

Live location tracking is a background process that uses sensor signals. Therefore, consuming the energy of the phone. However, we are constantly improving the energy efficiency of our SDKs. Current tests show that we drain less than Uber’s rider app kept in the pocket (without screen time). The caveat with most tests like that is that phones, user behaviors, and tracking environments differ significantly.

In tens of MBs per month on the device that is generating; lower single digit MBs per month on the device that is consuming.

Yes, you can configure webhooks to stream all movement, activity, and trip markers to your server in real-time.

You can access and query your data up to 30 days into the past.

The HyperTrack service runs as a separate component and it is still running when the app that started it is terminated.

Yes, HyperTrack currently provides an Android Views module to subscribe to device and trip notifications programatically. You can use the module to render your own mapping view with the mapping solution of your choice.