Changelogs

API requests browser

Changelogs is an API available to administrators that lets you browse all API requests made on a site. It lets you filter by methods, path, and even see modifications to a specific path in the API.

Browsing changelogs

To browse the changelogs you can make a request to

GET /changelogs

The summarized results show basic information about the affected path, the time, and a unique ID.

    {
      "path": "/api/vehicles/123",
      "system_time": "2022-05-05T00:51:15.986524+00:00",
      "user_id": "1",
      "id": "ea975489-2fb6-4024-955b-011a9254ebfc",
      "method": "PUT"
    },
    {
      "path": "/api/vehicles",
      "system_time": "2022-05-05T00:17:12.277080+00:00",
      "user_id": "1",
      "id": "40ae260c-9ef9-44ca-b7b7-4de175201b76",
      "method": "POST"
    },

🚧

User ID

Note that the User ID is a string because it can be a scoped user, with certain permissions.

      "user_id": "user_id=16&write=vehicles,assets",

The full param can be used to return detailed results of the request and response.

Filtering

Filtering is achieved with the following query params

query paramdescriptionexample
idsList of unique IDs to search (note that when passed it shows the full results)&ids=57f3845d-5727-48d2-839b-bad4c387945f
user_idsList of user IDs to filter for changes&user_ids=1,2,3
methodsMethods to filter by&methods=POST
pathSpecific path to search (accepts regex)path=/api/vehicles

👍

Regex paths

The path parameter accepts regex to match multiple results.

For example: matches any vehicle ID
&path=^/api/vehicles/?.*$

Filtering can also be achieved by using the results of the request or response. To do this you need to build a flattened key that points to the value you're searching for.

For example if the results of the changelogs are:

{
    "system_time": "2022-04-29T06:59:03.564102+00:00",
    "user_id": "60",
    "request": {},
    "response": {
        "status": "200 OK",
        "status_code": 200,
        "data": {
            "first_name": "John",
            "email": "[email protected]",
            "groups": [1,2,3],
            "properties": {
                "certified": true
            },
            "id": 123
        }
    }
}

You can target specific values by navigating the json fields in dot notation, starting from request or response.

query paramdescription
response.data.first_name=JohnFilters results by all first_names = John
response.data.groups.0=2Filters results whose groups array contains group ID 2
response.data.properties.types=[27]Filters the first element in an array with a value of 27
response.data.properties.types.0=27Filters for any element in an array with a value of 27
response.data.properties.certified=trueFilters results by a custom property with a boolean true value
response.data.id=123Filter results by the response ID (combined with method POST can be used to search creation of entities)

Navigating changelogs

In order to navigate the changelogs you need to look at the values of total and offset.

The total gives you the total amount of results from the changelogs request, while offset indicates how far from the first result you must navigate to reach the total. Note that you navigate the changelogs until the count plus the offset equals the total.

query paramdescription
countamount of results in changelogs request
totaltotal number of changes to navigate through
offsetnumber of results to skip until you reach the total
// showing first 25 results (count) out of a total of 53
GET /changelogs?limit=25
{
    "count": 25,
    "query": {},
    "total": 53,
    "data": [],
    "offset": 0
}

// showing next 25 results 
GET /changelogs?limit=25&offset=25
{
    "count": 25,
    "query": {},
    "total": 53,
    "data": [],
    "offset": 25
}

// showing last 3 results after applying an offset with the first 50
GET /changelogs?limit=25&offset=50
{
    "count": 3,
    "query": {},
    "total": 53,
    "data": [],
    "offset": 50
}

Modifications

Modifications are specific changes done to the responses of certain resources within the API. You may want to browse whenever certain properties have changed over time, this API is useful for that.

Browsing modifications

To browse modifications you can make a GET request to

GET /changelogs/modifications

The modifications occur over one of the following specific resources, which must be passed as a query param resource:

  • vehicles
  • assets
  • geofences
  • geofence_types

Vehicle modifications request
GET /changelogs/modifications?resource=vehicles

This request essentially filters only PUTs made to the resource requested.

Filtering

You can filter the results to multiple resource IDs, or group IDs using the query params ids & groups

query paramdescriptionexample
idsList of resource IDs to search for&ids=1,2,3
groupsList of group IDs to search for&groups=1,2,3

You can also filter only specific changes to a resource using the query param changes. This param allows you to filter when only specific fields within the resource change over time.

For example if you want to see the changes of a particular vehicle's property over time you can use:
&changes=properties.OrderNumber

The results will give you something like this

// GET /changelogs/modifications?resource=vehicles&ids=1&changes=properties.OrderNumber
    {
      "properties.OrderNumber": 8012635798,
      "$$user_id": "3",
      "$$id": "854fdd5b-330a-4632-b920-c6e43efc5158",
      "$$system_time": "2022-05-03T21:27:03.369956+00:00",
      "$$object": 1
    },
    {
      "properties.OrderNumber": 8012635207,
      "$$user_id": "3",
      "$$id": "07818630-2f5a-4402-a5f7-46d35ea1e85b",
      "$$system_time": "2022-05-03T19:21:15.476119+00:00",
      "$$object": 1
    },

Where the $$ fields refer to the user Id that made the change, the unique identifier for that changelog request, the time of the change, and the ID of the resource that was filtered.

Navigating modifications

In order to navigate modifications you have to keep in mind two things: pointer & section.

Pointer

The pointer indicates which changelog modifications are being traversed across the universe of all changes (notice that there's no total, this will become more clear later).

For every changelog modification response there's a key called next_pointer that indicates how you should modify the pointer param for the next set of modification changes. In a way the pointer is similar to the changelog's offset in that it can be moved, however it's different in that it depends on a value from the returned results to update (next_pointer), and it's moved until the next_pointer = -1

For example:

// Vehicle modifications for OrderNumber which returns a count of 6 results
// Since next_pointer = -1 these are all the possible results
GET /changelogs/modifications?resource=vehicles&ids=1&changes=properties.OrderNumber

{
    "count": 6,
    "query": {
        "resource": "vehicles",
        "pointer": 0,
        "section": 1,
        "ids": [
            1
        ],
        "to": "2022-05-03T23:59:59+00:00",
        "limit": 100,
        "from": "2022-05-03T00:00:00+00:00",
        "changes": [
            "properties.OrderNumber"
        ]
    },
    "data": [],
    "next_pointer": -1,
    "sections": 1
}
// Same vehicle modifications for OrderNumber which returns a count of 2 results since we limit it to 2 
// Since next_pointer is != -1 our next request will have a pointer value = 10

GET /changelogs/modifications?resource=vehicles&ids=1&changes=properties.OrderNumber&limit=2
{
    "count": 2,
    "query": {
        "resource": "vehicles",
        "pointer": 0,
        "section": 1,
        "ids": [
            1
        ],
        "to": "2022-05-03T23:59:59+00:00",
        "limit": 2,
        "from": "2022-05-03T00:00:00+00:00",
        "changes": [
            "properties.OrderNumber"
        ]
    },
    "data": [],
    "next_pointer": 10,
    "sections": 1
}

// In our example the next pointer values increase to 21, 33, 41, before finally reaching -1

GET /changelogs/modifications?resource=vehicles&ids=1&changes=properties.OrderNumber&limit=2&pointer=21
GET /changelogs/modifications?resource=vehicles&ids=1&changes=properties.OrderNumber&limit=2&pointer=33
GET /changelogs/modifications?resource=vehicles&ids=1&changes=properties.OrderNumber&limit=2&pointer=41

// Once it reaches -1 we know we're done

🚧

Results when traversing multiple pages

Keep in mind that anytime you move a pointer to request more changelog modifications you're going to have repeated values where the last modification of one page is equal to the next modification of the next page.

Sections

The next thing to watch out for are the sections, these are large data sets that must be traversed to obtain all the results.

// Vehicle modifications for OrderNumber which returns 14 sections 
// The first section must be traversed until next_pointer = -1
GET /changelogs/modifications?resource=vehicles&groups=123&changes=properties.OrderNumber

{
    "count": 100,
    "query": {
      "resource": "vehicles",
      "pointer": 0,
      "section": 1,
      "ids": [],
      "to": "2022-05-03T08:30:00-04:00",
      "limit": 100,
      "from": "2022-05-03T00:00:00-04:00",
      "changes": [
        "properties.OrderNumber"
      ]
    },
    "data": [],
    "next_pointer": 147,
    "sections": 14
}

GET /changelogs/modifications?resource=vehicles&groups=123&changes=properties.OrderNumber&pointer=147
GET /changelogs/modifications?resource=vehicles&groups=123&changes=properties.OrderNumber&pointer=XXX...

// The last page of the first section may be 
GET /changelogs/modifications?resource=vehicles&groups=123&changes=properties.OrderNumber&pointer=1034

{
    "count": 23,
    "query": {
      "resource": "vehicles",
      "pointer": 1034,
      "section": 1,
      "ids": [],
      "to": "2022-05-03T08:30:00-04:00",
      "limit": 100,
      "from": "2022-05-03T00:00:00-04:00",
      "changes": [
        "properties.OrderNumber"
      ]
    },
    "data": [],
    "next_pointer": -1,
    "sections": 14
}

// At which point the next section must be traversed until you reach all sections
GET /changelogs/modifications?resource=vehicles&groups=123&changes=properties.OrderNumber&pointer=1034&section=2

{
    "count": 100,
    "query": {
      "resource": "vehicles",
      "pointer": 0,
      "section": 2,
      "ids": [],
      "to": "2022-05-03T08:30:00-04:00",
      "limit": 100,
      "from": "2022-05-03T00:00:00-04:00",
      "changes": [
        "properties.OrderNumber"
      ]
    },
    "data": [],
    "next_pointer": 40,
    "sections": 14
}

// Once your section = sections and next_pointer = -1 you've traversed all sections of all possible changes and you're done