Telematics Sync

GPS and diagnostic data for telematics synchronization

Overview

The /fleet/vehicles/stats/feed endpoint allows you to sync GPS and diagnostic data. Each request will return all updates to vehicle state since the last time you made a request.

This endpoint supports querying a wide variety of vehicle stats data. See Query Parameters for details on available statistics.

This endpoint uses a cursor to keep track of the feed. Each request returns an endCursor that represents the last data point in the response. If you make another request and provide the endCursor as a query parameter, you'll receive all the vehicle stats updates since the last request you made.

A request with no after returns the last known stats in the query.

Here's an example sequence:

RequestDescription
Request #1GET /fleet/vehicles/stats/feed?types=gps
Returns last known gps data for all vehicles
endCursor: abcdefg
Request #2GET /fleet/vehicles/stats/feed?types=gps&after=abcdefg
Returns GPS updates since the last cursor (abcdefg)
endCursor: hijklmnop
Request #3GET /fleet/vehicles/stats/feed?types=gps&after=hijklmnop
Returns GPS updates since the last cursor (hijklmnop)
endCursor: qrstuvwxyz
...

The frequency of the queries depends on your use case. If you need a real-time solution, you could make these queries every 5 seconds. If you're doing a daily sync, you could make the queries every 24 hours. In either case, each new request returns all the vehicle stats updates since the last request.

Let's look at an in-depth example, using engineStates as the stat type:

Request #1

The first request to /feed to kicks off the synchronization process. A cursor should not be provided in the request:

curl --request GET 'https://api.samsara.com/fleet/vehicles/stats/feed' \
--header 'Authorization: Bearer <<token>>' \
-d types='engineStates' \
-G

The response will contain the last known engine state of all vehicles. The data array contains an entry for each vehicle in the fleet. In this case, there is only one vehicle, called Little Red. The engineStates array contains the last known engine state for the vehicle. In this case, the vehicle has been Off since 2020-07-03T02:11:51Z.

The pagination object contains information about the data feed. hasNextPage is false which indicates that there are no more vehicles on this page and no updates to engine state are immediately available. We should save the endCursor and use it in our next request to get updates.

{
    "data": [
        {
            "engineStates": [
                {
                    "time": "2020-07-03T02:11:51Z",
                    "value": "Off"
                }
            ],
            "id": "281474977075805",
            "name": "Little Red"
        }
    ],
    "pagination": {
        "endCursor": "c5088db7-6d2f-4106-8bc1-0c8028ae0c2b",
        "hasNextPage": false
    }
}

You can choose how often you want to poll the endpoint for new data. You could poll in 5 seconds for a real-time feed, or you could poll in 24 hours for a daily sync. In either case, the next request will return the updates since the last call you made.

Request #2

Now we want to request the updates since the last time we made a call. We provide the endCursor from the request above to the after query parameter:

curl --request GET 'https://api.samsara.com/fleet/vehicles/stats/feed' \
--header 'Authorization: Bearer <<token>>' \
-d types='engineStates' \
-d after='c5088db7-6d2f-4106-8bc1-0c8028ae0c2b' \
-G

The response contains all updates to engine state since the last time we made a request. In this case, there are two updates: the vehicle turned On at 2020-07-05T21:48:42Z and then it turned Off at 2020-07-05T21:56:24Z. Both of these events occurred since the last time we made a request.

{
    "data": [
        {
            "engineStates": [
                {
                    "time": "2020-07-05T21:48:42Z",
                    "value": "On"
                },
                {
                    "time": "2020-07-05T21:56:24Z",
                    "value": "Off"
                },
            ],
            "id": "281474977075805",
            "name": "Little Red"
        }
    ],
    "pagination": {
        "endCursor": "d3e945ab-8503-4260-8ec3-d13b1d1a7751",
        "hasNextPage": false
    }
}

You'll notice that these events occurred two days after the event from Request #1. This is because an initial request the /feed endpoint will always return the last known stat values (even if it was from a long time ago).

Request #3

Now we make another request to get the next set of updates since our last call. Once again, you provide the endCursor from the request above to the after query parameter:

curl --request GET 'https://api.samsara.com/fleet/vehicles/stats/feed' \
--header 'Authorization: Bearer <<token>>' \
-d types='engineStates' \
-d after='d3e945ab-8503-4260-8ec3-d13b1d1a7751' \
-G

In this case, the data array is empty because there have been no changes to engine state since the last request we made.

{
    "data": [],
    "pagination": {
        "endCursor": "cc864539-7b61-4e90-90c8-713f3ac959cd",
        "hasNextPage": false
    }
}

We can continue using making requests in the fashion above to continuously sync data.

Sample Code

This sample code calls the /feed endpoint in a continuous loop to show how to use the pagination information to request vehicle stats updates. The secondsToWait variable is the number of seconds to wait between each request. You can set this value to whatever suits your use case. You should not request updates more frequently than every 5 seconds.

import requests
import json
import time

url = "https://api.samsara.com/fleet/vehicles/stats/feed"
headers = {"Authorization": "Bearer <<token>>"}
params = {"types": "engineStates"}
secondsToWait = 5

while True:
    response = requests.request("GET", url, headers=headers, params=params).json()

    # For each vehicle in the list, process its data
    for vehicle in response["data"]:
        for data_point in vehicle["engineStates"]
            # Do something with each data point

    # Set the `after` parameter for the next request
    params["after"] = response["pagination"]["endCursor"]

    # If there is no more data immediately available, sleep
    if not response["pagination"]["hasNextPage"]:
        time.sleep(secondsToWait)