Navbar
👋 Have a question? Ask us!
cURL NodeJS Python Java PHP Ruby Swift ObjC
>

Introduction

HyperTrack is the API for anything that moves with commercial value. From startups to enterprises worldwide, product development teams build live location use cases with HyperTrack to power business efficiency and product experience.

Learn how to build live location use cases for your business with HyperTrack. Start with your use case.

Pre-requisites to build a live location use case with HyperTrack:

Getting Started

getting-started > Experience it first

This is best for product development teams who want to experience HyperTrack in the wild before developing their use case. Get the HyperTrack Live app from the public stores.

getting-started > Quickstarts

This is best for developers who want to play with the HyperTrack APIs on a test app built with the HyperTrack SDK. Clone the HyperTrack Quickstart app from Github.

getting-started > Install SDK

This is best for mobile app developers who are ready to install the HyperTrack SDK to their apps so their teams can build live location use cases with HyperTrack. Follow these instructions to install the SDK.

getting-started > Build new app

This is best for product development teams who are starting to build an app for their business and want to kickstart with an open sourced app built with HyperTrack for their use case. Fork or clone the app that best represents your use case.

Guides

These guides presume that you have trackable devices on your account, either by:

guides > Track devices with the API

The quickest and most popular way to use HyperTrack is to track devices with the API. This guide will show you how to:

guides > track-devices-with-the-api > Start and stop tracking

HyperTrack APIs give you the power to control tracking on all devices using apps with HyperTrack SDKs pointing to your account.

Get the keys

Get your AccountID and SecretKey. You can get these from the setup page on your HyperTrack dashboard.

setup

Get the device ID(s) of the user(s) you want to track

The SDK should have added a device name and metadata upon initialization in the user's app: (iOS, Android).

If you have already sent and stored this information to your servers, get the user's device ID from your application database. Else, get the list of registered devices from the Devices API and use the device name or metadata to identify the user(s) you want to track.

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 users easier. Developers often add unique identifiers, grouping information, or annotations that are frequently accessed for devices.

Device name and custom metadata

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

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. Additionally, the Devices API provides you an ability to update device name and metadata via an HTTP PATCH.

Start tracking

This is typically done when the app user starts working (e.g. app login, start of working hours, work assignment, etc.).

POST /devices/{device_id}/start to start tracking.

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

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

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/devices/{device_id}/start",
  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/devices/{device_id}/start", 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}/start")
  .post(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}/start');
$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'
require 'json'

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

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/devices/{device_id}/start")! 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/devices/{device_id}/start"]
                                                       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];

HTTP 200 - Tracking command was sent (no content)

Authentication: Basic Auth

Path Parameters:

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

Set custom markers (OPTIONAL)

Use this when you want to add an action performed by the app user in the location timeline of the user.

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 devices, HyperTrack provides the ability to set custom markers.

To set a custom 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 device summary.

Stop tracking

This is important to protect the privacy of workers. Use this when app user stops working (e.g. app logout, end of working hours, all assigned work completed, etc.).

POST /devices/{device_id}/stop to stop tracking.

Authentication: Basic Auth

Path Parameters:

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

guides > track-devices-with-the-api > Stream events via webhooks

Use webhooks to ingest live location, activity, outage and other movement context of your devices from HyperTrack to your server end point. Works best when building live location experiences and applications on your server.

Webhooks setup 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

The following Webhooks are posted.

Locations

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

{
  "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).

Device status

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

{
  "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. Please read here to understand how HyperTrack tracks device status.

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).

HyperTrack supports 3 types of activity transitions: walk, drive, and stop.

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

Battery

Battery status changes. Values include low, normal and charging

{
    "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.

guides > track-devices-with-the-api > Get live location from the API

Use the Devices API to get the live location and device status of one or more devices. Works best when building dispatch, assignment and routing applications, and require live location information on demand.

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": { ... }
}

All tracked devices are available through the Devices API. Each device entity contains the following data:

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

It can be one of the following: active, inactive or disconnected. See here for a detailed description.

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, or drive.

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 sending location updates and in that case, the device_status.data object is contains reason property`. These reasons can be one of the following below:

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.

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

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

guides > track-devices-with-the-api > View devices on the map

Go to Views on your HyperTrack dashboard to map all devices that you intend to track.

Map view of all devices

Map View

Day and timezone select

calendar select

Users can select the day and timezone for which they want to view the list of devices on a map, and drill down into individual devices and their histories.

Device status and metadata device status

Devices in the list show a status bar and metadata for each device. For selected day, the status bar indicates the duration of stop, walk, drive, inactive and disconnected for the device. Metadata shows the values set in the device metadata JSON, and shows the corresponding keys on hover.

Live location of a device

live location view

The view for today shows live location of devices on the map with last known locations. Live locations automatically update in the view as the device moves. Hovering on live location opens a card with the following information:

There are additional visual elements to make the live location of other devices come alive in a way that is consistent with on-device views of location in popular mapping apps.

Device timeline

device timeline "Device Timeline")

Clicking a device in the list or clicking the dot on the map shows the device timeline.

Device info

device info card

Selecting a device gives you the option to look at device info, including:

guides > track-devices-with-the-api > Filter views 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 for iOS or Android.

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.

guides > track-devices-with-the-api > Embed views in your dashboard

Embed views require the HyperTrack publishable key. Get your publishable key from the Setup page on your HyperTrack dashboard.

Aggregate views

Aggregate View

The browser URL for aggregate views in the dashboard are in the form:

https://dashboard.hypertrack.com/devices?{var1}={foo}&{var2}={bar}

The corresponding embed URL would be:

https://embed.hypertrack.com/devices?publishable_key={publishable_key}&{var1}={foo}&{var2}={bar}

Single device view

Single Device View

The browser URL for single device views in the dashboard are in the form:

https://dashboard.hypertrack.com/devices/{deviceID}?{var1}={foo}&{var2}={bar}

The corresponding embed URL would be:

https://dashboard.hypertrack.com/devices/{deviceID}?publishable_key={publishable_key}&{var1}={foo}&{var2}={bar}

If you prefer, the Devices API returns embed_url for single device views that you may directly use.

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:

guides > track-devices-with-the-api > Delete devices

Use delete to delete devices and stop tracking them permanently. This is typically needed when the user has abandoned the app or left the business. Deleting a device will retain the tracking history of the device, and will be available through APIs and views. The device will stop tracking further and you will be unable to start tracking the same device ID again.

guides > Track trips with destination

One of the more popular use cases of HyperTrack is live location sharing of an order with customers. From Uber-for-X startups to enterprises delivering products and services to customers, "where's my order?" is a moment of anxiety that businesses want to handle better. Businesses can improve NPS scores and save money by providing visibility to customers and ops teams about the live location of the order, with ETA and delay notifications. HyperTrack has open sourced popular sample apps for Live Location Sharing and Ridesharing, with detailed tutorials to integrate trips with destination for your application. This guide will show you how to:

guides > track-trips-with-destination > Start and complete 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"
  },
  "device_info": {
    "sdk_version": "3.3.2",
    "os_version": "12.4"
  },
  "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 the Trips API when you want to track the movement of the device to an expected destination. Post the destination for the device, and get estimates (route/ETA) to destination, shareable URL for customers, embed URL for ops dashboards, and markers for activity and outages as the device moves. Completed trips include a summary with total duration, distance and steps.

Starting and completing trips would automatically control the start and stop of tracking on the device. This way, you manage tracking through just one API.

The device would start tracking (unless already tracking) when you start a trip for the device. The device will stop tracking when all active trips for device are completed. HyperTrack uses a combination of silent push notifications and sync method on the SDK to ensure that tracking starts for the device.

guides > track-trips-with-destination > Get route and ETA

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];

Trip with destination returns an estimated route polyline and estimated time of arrival (ETA).

To start 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.

Share URL with customer

tracking experience

Trips API generates a share_URL for each trip with destination. More details can be found in the Trips API reference.

Share URL has the following structure: https://trck.at/{7_digit_tracking_id}. This makes it a total of 23 characters, and therefore a friendly URL to share via text or other messengers. Share URLs stay accessible permanently and show trip summary after trip completion.

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 ]
          , ... ]
      }
    }
  }
}

Route and estimate objects

The Trips API responds with an active trip object that returns the original payload with additional properties.

A new estimate object is included in the trips payload. HyperTrack provides estimates for every trip with a destination. The object includes information about:

guides > track-trips-with-destination > Track delays for scheduled trip

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. Use this when the order has a time commitment to the customer. When set, HyperTrack will send trip delay webhooks when the device is highly likely to miss that time commitment.

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 ]
          , ... ]
      }
    }
  }
}

The trips payload has arrived_at and exited_at properties in the destination object. These are null initially. As soon as the tracked device arrives at the destination, the arrival time gets updated. When the device leaves the the destination, the exit time gets set. You can use these properties to identify time spent at a destination.

guides > track-trips-with-destination > Embed trip view in dashboard

trip embed view

The Trip payload includes the views object. Every trip gets assigned unique URLs to share and embed views of the trip. The URLs will remain active after trip completion. In that case, the views will show a summary of the trip, along with destination marker, start and complete locations, distance, duration, arrival time, device info, trip metadata, and the actual route taken to the destination.

While shareable views are accessible to everyone with the URL, embed views include the HyperTrack publishable key. The embed_URL includes the publishable key and is available to use as-is. That said, your publishable key is available in the Setup page of your HyperTrack dashboard.

The embed URL format is https://embed.hypertrack.com/trips/{trip_id}?publishable_key={publishable_key}

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:

Trips API generates embed_URL for all trips. More details can be found in the Trips API reference.

guides > track-trips-with-destination > Get trip updates on webhooks

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:

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

Trip start

For every new trip, start 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.

{
  "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 start. 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 (start, 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.

guides > track-trips-with-destination > Stream trip data to native apps

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.

guides > track-trips-with-destination > Get trip summary

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": "stopped_programmatically"
        }
      },
      {
        "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. Additionally, when executing a Trips GET API call on a single trip_id a summary object is returned with the latest data for the trip.

guides > Track trips with geofences

Workforce automation, logistics and fleet management apps are often built for users to fulfill a list of jobs assigned at the start of the work day. User visits these places and then returns to base. Business wants to track how time was spent, what routes were taken, and map it with enterprise application data to measure productivity scores and improve efficiency. This guide will show you how to:

guides > track-trips-with-geofences > Start and complete trip

Use the Trips API when you want to track the movement of the device to a list of geofences. Post the geofences as an array to get get arrival, exit, time spent and route to geofences, embed URL for ops dashboards, and markers for activity and outages as the device moves. Completed trips include a summary with total duration, distance and steps.

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];

To start such a trip, the geofences array is required. The array should include objects with a GeoJSON object called geometry. Both Point and Polygon are supported in the GeoJSON object. Point will set a circular geofence area with a radius of 30 meters by default. Polygon will set a polygon geofence through an array of locations where the first and last location must be the same.

Use geofence metadata to identify each geofence in HyperTrack with the place of interest in your application. The metadata is returned through the respective APIs, webhooks, and views.

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 that returns the original payload with additional properties.

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 the trip at the end of the work day, e.g. when all jobs are done, end of work hours, assets returns to the station.

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"
  },
  "device_info": {
    "sdk_version": "3.3.2",
    "os_version": "12.4"
  },
  "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": {
     ...
  }
}

guides > track-trips-with-geofences > Get arrival and exit

The geofence objects in the trips payload have arrived_at and exited_at properties. These are null initially. As soon as the tracked device enters the geofence, arrival time is updated for that geofence. Similarly, when the device exits the geofence, the exit time is set for that geofence.

Update geofence metadata

Users who want to update geofence metadata after trip creation can PATCH geofence metadata. Use this when new application data has been recieved about that place of interest, and you wish to display them in views and add them to the trip summary object for record.

guides > track-trips-with-geofences > Get time spent and route to

The geofence markers in trip summary have duration and route_to properties. The route_to object includes distance, duration, start location and array of locations for the route from previous geofence (or from start in case of the first geofence).

time spent and route to

guides > track-trips-with-geofences > Embed trip view in dashboard

geofences embed view

The Trip payload includes the views object. Every trip gets assigned unique URLs to share and embed views of the trip. The URLs will remain active after trip completion. In that case, the views will show a summary of the trip, along with geofence markers, start and complete location, distance, duration, arrival time, device info, trip metadata, and the actual route taken to the destination.

While shareable views are accessible to everyone with the URL, embed views include the HyperTrack publishable key. The embed_URL includes the publishable key and is available to use as-is. That said, your publishable key is available in the Setup page of your HyperTrack dashboard.

The embed URL format is https://embed.hypertrack.com/trips/{trip_id}?publishable_key={publishable_key}

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:

Trips API generates embed_URL for all trips. More details can be found in the Trips API reference.

guides > track-trips-with-geofences > Get trip summary data

Trip summary provides powerful data about the device's trip visiting geofences.

References

references > APIs

HyperTrack APIs allow to manage 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. Using the APIs allows you to obtain the full state of all tracked devices and trips.

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

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.

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.

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.

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

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.

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.

references > apis > Devices

Manage devices on the HyperTrack platform.

references > apis > devices > 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. Please read here to understand how HyperTrack tracks device status.
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, or drive
device_status.data.reason string For inactive devices only.

Can be one of:

location_permissions_denied,
location_services_disabled,
motion_activity_permissions_denied,
motion_activity_services_disabled,
motion_activity_services_unavailable,
stopped_programmatically,
tracking_service_terminated,
unexpected
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

references > apis > devices > 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. Please read here to understand how HyperTrack tracks device status.
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, or drive
device_status.data.reason string For inactive devices only.

Can be one of:

location_permissions_denied,
location_services_disabled,
motion_activity_permissions_denied,
motion_activity_services_disabled,
motion_activity_services_unavailable,
stopped_programmatically,
tracking_service_terminated,
unexpected
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

references > apis > devices > POST /devices/{device_id}/start

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

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

const options = {
  method: "POST",
  url: "https://v3.api.hypertrack.com/devices/{device_id}/start",
  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/devices/{device_id}/start", 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}/start")
  .post(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}/start');
$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'
require 'json'

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

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/devices/{device_id}/start")! 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/devices/{device_id}/start"]
                                                       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];

HTTP 200 - Tracking command was sent (no content)

Start tracking.

Authentication: Basic Auth

Path Parameters

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

references > apis > devices > POST /devices/{device_id}/stop

Stop tracking.

Authentication: Basic Auth

Path Parameters

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

references > apis > devices > 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

references > apis > devices > 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. Once it is removed, the device will not be able send location data.

Authentication: Basic Auth

Path Parameters

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

references > apis > Trips

Manage Trips on the HyperTrack platform.

references > apis > trips > 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];

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": "Polygon",
        "coordinates": [
            [-121.3980960195712, 38.7940386903944],
            [-121.3990960195712, 38.7940386903944],
            [-121.3990960195712, 38.7930386903944],
            [-121.3980960195712, 38.7930386903944]
          ]
      },
      "metadata": {
        "stop_id": "12345XYZ",
        "stop_name": "SF office"
      }
    }
  ],
  "metadata": {
    "shift_id": "ABC123"
  }
}'

Start 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 or Polygon
geofences[].geometry.type string Either Point or Polygon
geofences[].geometry.coordinates array Array of longitude and latitude in case of Point type; Polygon type contains array of positions (First and last positions need to be same to complete the loop
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
  },
  "device_info": {
    "sdk_version": "3.3.2",
    "os_version": "12.4"
  },
  "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 ]
          , ... ]
      }
    }
  }
}

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
metadata object Metadata provided at trip start

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.

If trip with same destination and metadata already exist, API will return existing trip with status 200.

references > apis > trips > 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 ]
                  , ... ]
              }
          }
      }
    },
    {
      "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 and Polygon
geofences[].geometry.type string Either Point or Polygon
geofences[].geometry.coordinates array Array of longitude and latitude in case of Point or array of positions in case if Polygon (First and last positions need to be same to complete the loop)
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30) for type Point
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
summary object Trip summary. Available for completed trips as well as for ongoing trips for a given trip_id
metadata object Metadata provided at trip start

references > apis > trips > 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"
  },
  "device_info": {
    "sdk_version": "3.3.2",
    "os_version": "12.4"
  },
  "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 and Polygon
geofences[].geometry.type string Either Point or Polygon
geofences[].geometry.coordinates array Array of longitude and latitude in case of Point or array of positions in case if Polygon (First and last positions need to be same to complete the loop)
geofences[].radius int Defines the radius (in meters) of a circular geofence (optional, default is 30) for type Point
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
summary object Trip summary. Available for completed trips as well as for ongoing trips for a given trip_id
metadata object Metadata provided at trip start
references > apis > trips > get-trips-trip_id > Trip summary

For completed and ongoing 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": "stopped_programmatically"
        }
      },
      {
        "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

references > apis > trips > PATCH /trips/{trip_id}/geofence_id/{geofence_id}

Patch trip geofence data

payload='{
  "metadata": {
    "geofence_stop_id": "ABC123"
  }
}'

curl -X PATCH \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}/geofence/{geofence_id} \
  -H 'Content-Type: application/json' \
  -d $payload

HTTP 200 - trips geofence metadata is updated

Update a trip geofence metadata.

Authentication: Basic Auth

Path Parameters

trip_id - a string representing the trip ID

geofence_id - a string representing the geofence ID for which metadata is being updated

references > apis > trips > GET /trips/{trip_id}/geofence_id/{geofence_id}

Get trip geofence data

curl -X GET \
  -u {AccountId}:{SecretKey} \
  https://v3.api.hypertrack.com/trips/{trip_id}/geofence/{geofence_id} \
  -H 'Content-Type: application/json'

HTTP 200 - Geofence payload


{
    "created_at": "2019-12-19T21:36:06.259005+00:00",
    "geofence_id": "f558e8fe-b71f-4529-b94c-2b1f242de873",
    "device_ids": [
        "caeeecf9-6130-47c3-bef8-63ac27df3d51"
    ],
    "metadata": {
        "metadata_key": "value"
    },
    "geometry": {
        "type": "Point",
        "coordinates": [
            35.0380182196383,
            47.8208697707263
        ]
    },
    "radius": 30.0
}

Get trip geofence.

Authentication: Basic Auth

Path Parameters

trip_id - a string representing the trip ID

geofence_id - a string representing the geofence ID to get

references > apis > trips > 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"
  },
  "device_info": {
    "sdk_version": "3.3.2",
    "os_version": "12.4"
  },
  "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 start

references > 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.

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.

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.

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.

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.

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.

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.

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. start 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"

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 start, destination arrival, destination exit, trip delays, and trip completion events

references > webhooks > 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

references > webhooks > 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. Please read here to understand how HyperTrack tracks device status.
data.activity string For active devices only, can be one walk,drive, or stop
data.reason string For inactive devices only.

Can be one of:

location_permissions_denied,
location_services_disabled,
motion_activity_permissions_denied,
motion_activity_services_disabled,
motion_activity_services_unavailable</code>,
stopped_programmatically,
tracking_service_terminated,
unexpected.
Please read here to understand how HyperTrack tracks device status.
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)

references > webhooks > 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)

references > webhooks > 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 start 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

references > SDKs

references > sdks > Android

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

references > sdks > android > Initialize

Initialize the SDK with your activity and publishable key only.

HyperTrack sdkInstance = HyperTrack.getInstance(getApplicationContext(), 'your-publishable-key-here');
val sdkInstance = HyperTrack.getInstance(this as Context,  'your-publishable-key-here')
Parameter Type Description
context Context Application Context
publishableKey String Your publishable key from the dashboard

references > sdks > android > Start tracking

Start tracking.

sdkInstance.start();
sdkInstance.start()

references > sdks > android > Stop tracking

Stop tracking.

sdkInstance.stop();
sdkInstance.stop()

references > sdks > android > Check tracking status

Check tracking status.

boolean isTrackingServiceRunning = sdkInstance.isRunning();
val isTrackingServiceRunning = sdkInstance.isRunning()

references > sdks > android > Get device ID

Obtain device identifier.

String deviceID = sdkInstance.getDeviceId();
val deviceID = sdkInstance.getDeviceId()

references > sdks > android > Set name and metadata

Set name and metadata for device tracking data.

sdkInstance.setDeviceName("your-custom-device-name");

// create new metadata map
Map<String,Object> myMetadata = new HashMap<>();
// add external id to metadata
myMetadata.put("external-id", "your-external-id");

sdkInstance.setDeviceMetadata(myMetadata);
sdkInstance
  .setDeviceName("your-custom-device-name")
  .setDeviceMetadata(mapOf("external-id" to "your-external-id"))
Parameter Type Description
name String Custom device name
metaData Map or String Custom metadata as key-value pair or valid JSON String

references > sdks > android > Create trip marker

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

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

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

sdkInstance.addTripMarker(payload);
sdkInstance.addTripMarker(mapOf("item" to "Martin D-18", "price" to 7.75))
Parameter Type Description
payload Map or valid JSON string Trip marker data as key-value pair

references > sdks > android > 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.

sdkInstance.setTrackingNotificationConfig(
        new ServiceNotificationConfig(
          title,
          body,
          R.drawable.small_notification_icon,
          R.drawable.large_notification_icon,
          pendingIntent
       )
);
sdkInstance.setTrackingNotificationConfig(
    ServiceNotificationConfig(
      title,
      body,
      R.drawable.small_notification_icon,
      R.drawable.large_notification_icon,
      pendingIntent
   )
)

You can use builder, if you only need to override some of default properties or service notification config constructor to define all of them. Config options follow:

Parameter Type Description
title String Title (optional). Set to null to keep the default title
body String Body (optional). Set to null to keep the default body
smallIconId int Notification large icon ID
largeIconId int Notification large icon ID
pendingIntent PendingIntent Pending intent for notification click action

references > sdks > android > Attach sdk events handler

If you want to be notified about significant events, that occur during SDK initialization / tracking, you should attach listener (delegate, handler) to sdk instance. E.g. common issue is when tracking was started, but no actual location data is received due to location service been disabled on a os wide level. To address such an issue you can attach following

sdkInstance.addTrackingListener(new TrackingStateObserver.OnTrackingStateChangeListener() {
    @Override public void onError(TrackingError trackingError) {
        if (trackingError != null && trackingError.code == TrackingError.GPS_PROVIDER_DISABLED_ERROR) {
            String contentTitle = "Tracking isn't working";
            String contentText = "Please enable location service for tracking";
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    context, 42, new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS),
                    PendingIntent.FLAG_ONE_SHOT
            );
            sdkInstance.setTrackingNotificationConfig(
                new ServiceNotificationConfig.Builder()
                        .setContentIntent(pendingIntent)
                        .setContentText(contentText)
                        .setContentTitle(contentTitle)
                        .build()
            );
        }
    }

    @Override public void onTrackingStart() { }
    @Override public void onTrackingStop() { }
});
sdkInstance.addTrackingListener(object : TrackingStateObserver.OnTrackingStateChangeListener() {
    override fun onError(trackingError: TrackingError?) {
        trackingError?.let {
            when (trackingError.code) {
                TrackingError.GPS_PROVIDER_DISABLED_ERROR -> sdkInstance.setTrackingNotificationConfig(
                        ServiceNotificationConfig.Builder()
                                .setContentTitle("Tracking isn't working, please enable location services in settings")
                                .setLargeIcon(R.drawable.ic_green)
                                .build()
                )
                else -> Log.d(TAG, "Tracking failed with error code $it")
            }
        }            }

    override fun onTrackingStart() { }
    override fun onTrackingStop() { }
})
Parameter Type Description
trackingStateListener TrackingStateObserver.OnTrackingStateChangeListener Appropriate object methods would be called in case if significant event occurs

references > sdks > iOS

This reference shows methods available in the iOS SDK.

Refer to the integration guide for additional details.

references > sdks > ios > makeSDK(publishableKey:)

let publishableKey = HyperTrack.PublishableKey("PASTE_YOUR_PUBLISHABLE_KEY_HERE")!

switch HyperTrack.makeSDK(publishableKey: publishableKey) {
case let .success(hyperTrack):
  // Use `hyperTrack` instance
case let .failure(fatalError):
  // Handle errors, for example using switch
}
NSString *publishableKey = @"PASTE_YOUR_PUBLISHABLE_KEY_HERE";

HTResult *result = [HTSDK makeSDKWithPublishableKey:publishableKey];
if (result.hyperTrack != nil) {
  // Use `hyperTrack` instance from `result.hyperTrack`
} else {
  // Handle errors, for example using switch:
  switch ([result.error code]) {
    case HTFatalErrorProductionLocationServicesUnavalible:
    case HTFatalErrorProductionMotionActivityServicesUnavalible:
      // Handle a case where device is fully untrackable (either iPhone 5 or lower
      // or not an iPhone
      break;
    case HTFatalErrorProductionMotionActivityPermissionsDenied:
      // Handle motion permissions denied error. Enabling permissions will
      // restart the app
    default:
      // Other errors should only happen during development
      break;
  }
}

Creates and returns an SDK interface or FatalError if there are blockers to successful initialization.

Multiple interfaces can be created without duplicating memory and resources.

Put the initialization call inside your AppDelegate's application:didFinishLaunchingWithOptions: method.

Parameter Type Description
publishableKey struct struct containing a non-empty string of publishable key provided in HyperTrack's dashboard setup page.

Returns: A Result with an instance for HyperTrack SDK or an error of type FatalError if there is a development or production blocker to SDK initialization.

references > sdks > ios > init(publishableKey:)

let publishableKey = HyperTrack.PublishableKey("PASTE_YOUR_PUBLISHABLE_KEY_HERE")!

if let hyperTrack = try? HyperTrack(publishableKey: publishableKey) {
  // Use `hyperTrack` instance
}
NSString *publishableKey = @"PASTE_YOUR_PUBLISHABLE_KEY_HERE";

HTSDK *hyperTrack = [[HTSDK alloc] initWithPublishableKey:publishableKey];
if (hyperTrack != nil) {
  // Use `hyperTrack` instance
}

Creates an interface for the SDK.

Multiple interfaces can be created without duplicating memory and resources.

Parameter Type Description
publishableKey struct struct containing a non-empty string of publishable key provided in HyperTrack's dashboard setup page.

Throws: An error of type FatalError if there is a development or production blocker to SDK initialization.

references > sdks > ios > isRunning

hyperTrack.isRunning
[hyperTrack isRunning];

Reflects tracking intent.

When SDK receives start command, it captures this intent. SDK tries to track until it receives a stop command or if it encounters one of the following errors: UnrestorableError.invalidPublishableKey, RestorableError.trialEnded, RestorableError.paymentDefault.

references > sdks > ios > deviceID

hyperTrack.deviceID
[hyperTrack deviceID]

A string used to identify a device uniquely.

references > sdks > ios > setDeviceName(_:)

Set name and metadata for device tracking data.

hyperTrack.setDeviceName("Device name")
hyperTrack.deviceName = @"Device name";
Parameter Type Description
deviceName String A human-readable string describing a device or its user.

references > sdks > ios > setDeviceMetadata(_:)

if let metadata = HyperTrack.Metadata(rawValue: ["key": "value"]) {
  hyperTrack.setDeviceMetadata(metadata)
} else {
  // Metadata can't be represented in JSON
}
NSDictionary *dictionary = @{@"key": @"value"};

HTMetadata *metadata = [[HTMetadata alloc] initWithDictionary:dictionary];
if (metadata != nil) {
  [self.hyperTrack setDeviceMetadata:metadata];
} else {
  // Metadata can't be represented in JSON
}

Sets the device metadata for the current device.

You can see the device metadata in device view in Dashboard or through APIs. Metadata can help you identify devices with your internal entities (for example, users and their IDs).

Parameter Type Description
metadata struct A Metadata struct that represents a valid JSON object.

references > sdks > ios > addTripMarker(_:)

if let metadata = HyperTrack.Metadata(rawValue: ["status": "PICKING_UP"]) {
  hyperTrack.addTripMarker(metadata)
} else {
  // Metadata can't be represented in JSON
}
NSDictionary *dictionary = @{@"status": @"PICKING_UP"};

HTMetadata *metadata = [[HTMetadata alloc] initWithDictionary:dictionary];
if (metadata != nil) {
  [self.hyperTrack addTripMarker:metadata];
} else {
  // Metadata can't be represented in JSON
}

Adds a new trip marker.

Use trip markers to mark a location at the current timestamp with metadata. This marker can represent any custom event in your system that you want to attach to location data (a moment when the delivery completed, worker checking in, etc.).

Parameter Type Description
marker struct A Metadata struct that represents a valid JSON object.

references > Views

references > 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.

references > views > android > 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 ...

references > views > android > get-device-status > 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
references > views > android > get-device-status > 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.
references > views > android > get-device-status > 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
references > views > android > get-device-status > 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
references > views > android > get-device-status > 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 start
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
references > views > android > get-device-status > trip-properties > Trip Estimate Properties
Estimate{
    arriveAt="",
    route=Route{ ... }
}
Method Type Description
getArriveAt() String Timestamp for estimated arrival
getRoute() Trip.Route Planned route segments to destination
references > views > android > get-device-status > trip-properties > 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 Duration in seconds
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
references > views > android > get-device-status > trip-properties > 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

references > views > android > 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 DRIVE, STOP, or WALK
hint String Health hint. Additional information about the health event
recordedAt String ISO 8601 date when the device status was recorded

references > views > android > Unsubscribe from updates

hypertrackView.stopAllUpdates();

You can stop receiving updates you are subscribed to.

references > Device Status

A device is either active or inactive at any given time.

references > device-status > Active

Location and activity data is tracking as expected.

references > device-status > Inactive

Location or activity data are not tracking. This could be due to one of a few reasons.

references > device-status > inactive > Reasons

Stopped programmatically: Tracking is stopped by the app. The app does not intend to track the device at this time.

Permissions disabled/denied: Location or activity permissions are disabled/denied by app user for all-apps/this-app.

Service unavailable on device: Location or activity services are unavailable, either due to OS terminating service for the app or hardware unavailability

Unexpected outage: Location or activity data from the device is missing, and no reason has been provided.

references > device-status > Disconnected

HyperTrack platform is unable to sync with the device.

HyperTrack is a cloud platform to track ground truth of the device. There are times when the platform goes out of sync with the device. If and when the connection between device and platform is restored, the platform syncs up offline data and updates it for consumption in the cloud.

In the event that the device never returns to sync with the platform (can happen when device is lost or app is uninstalled), the device status will remain disconnected.

To understand how tracking status is defined and used in HyperTrack API, please refer to the following:

references > 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.

references > 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)

references > http-errors > 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.

references > http-errors > trips-api > Unauthorized

{
  "message": "Unauthorized"
}

HTTP 401 (Unauthorized)

Potential reason: The Authorization header in the request is invalid or missing.

Potential actions:

references > http-errors > trips-api > 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.

references > http-errors > trips-api > 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 -).

references > http-errors > trips-api > 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:

references > http-errors > trips-api > 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:

references > http-errors > trips-api > 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.

references > http-errors > trips-api > 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:

references > http-errors > trips-api > Unauthorized

// HTTP Status: 401
{
  "message": "Unauthorized"
}

Potential reasons:

Potential actions:

references > http-errors > trips-api > 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:

references > http-errors > 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.

references > http-errors > devices-api > Unauthorized

{
  "message": "Unauthorized"
}

HTTP 401 (Unauthorized)

Potential reason: The Authorization header in the request is invalid or missing.

Potential actions:

references > http-errors > devices-api > 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:

references > http-errors > devices-api > 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:

references > http-errors > devices-api > 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:

references > http-errors > devices-api > 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:

references > http-errors > devices-api > 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.

Yes. HyperTrack batches up to 12 hours of data while the phone is disconnected from the Internet, and then syncs it up with the server when data connection resumes. Devices with A-GPS may require an active cellular connection for location to be available. These devices might not track as expected while offline.

Start/stop tracking of devices, and start/complete trip, are available only when device is online.