Skip to content

Pagination and Time Ranges

How Rhombus list operations return results in pages: lastEvaluatedKey cursors, page tokens, timestamp cursors and time windows, with loops in Python and JavaScript and the pitfalls that cause missed or duplicated results.

On this page

Operations that can return many results page them in one of a few styles. Each operation's API Reference page shows which fields it takes; this page explains how each style works.

StyleRequest fieldsResponse fieldLast page when
CursormaxPageSize, lastEvaluatedKey (sometimes inside pageRequest)lastEvaluatedKeylastEvaluatedKey is absent
Page tokenpageSize, pageTokenpageTokenpageToken is absent
Timestamp cursormaxPageSize, pageTimestampMslastEvaluatedTimestampMslastEvaluatedTimestampMs is absent
Time windowcreatedAfterMs, createdBeforeMs, limitnoneA page has fewer than limit events
Last itemmaxResults, lastTimestampMs, lastUuidnoneA page comes back empty

All timestamps are Unix epoch milliseconds.

Cursor pages

Most list operations take maxPageSize and lastEvaluatedKey, and return lastEvaluatedKey while more results remain. Send it back unchanged to get the next page; when the response has no lastEvaluatedKey, you have everything. For example, findAccessControlledDoors:

import os
import requests

URL = "https://api2.rhombussystems.com/api/component/findAccessControlledDoors"
HEADERS = {"x-auth-scheme": "api-token", "x-auth-apikey": os.environ["RHOMBUS_API_KEY"]}

doors, key = [], None
while True:
    body = {"maxPageSize": 100}
    if key:
        body["lastEvaluatedKey"] = key
    page = requests.post(URL, headers=HEADERS, json=body).json()
    if page.get("error"):
        raise RuntimeError(page.get("errorMsg"))
    doors += page.get("accessControlledDoors", [])
    key = page.get("lastEvaluatedKey")
    if not key:
        break

Some operations nest the same two fields in a pageRequest object ({"pageRequest": {"maxPageSize": 100, "lastEvaluatedKey": "…"}}) and return lastEvaluatedKey at the top level of the response.

  • Keep going until lastEvaluatedKey is absent. A page can hold fewer results than maxPageSize, or none at all, while more remain: results you aren't allowed to see are removed after the page is read.
  • Always set maxPageSize. Without it, some operations return every result in one response, and others apply their own default. Each operation has its own maximum, and a larger value is rejected with 400.
  • Treat lastEvaluatedKey as opaque. Don't build, edit or store it long-term. A value the server can't read isn't rejected: the operation starts again from the first page.
  • Keep the other fields the same on every page of one listing.

Page tokens

A few operations, such as getClipsWithProgress, use pageSize and pageToken instead. Send the pageToken from each response with the next request, and stop when the response has none. For getClipsWithProgress, pageSize is 1 to 200 and defaults to 100.

Timestamp cursors

getSavedClipsV2 returns lastEvaluatedTimestampMs. Send it as pageTimestampMs in the next request, and stop when the response doesn't include it. Set maxPageSize; it defaults to 100. As with cursors, a page can be short while more clips remain.

Time windows

Event history for doors and sensors, such as findComponentEventsByAccessControlledDoor, takes a window and a count instead of a cursor:

  • createdAfterMs and createdBeforeMs bound the window. createdBeforeMs is exclusive.
  • limit caps the number of events, the most recent first. Set it: without limit, every event in the window comes back in one response.

To read further back, repeat the request with createdBeforeMs set to one millisecond after the oldest event you received, and drop events you already have by their UUID. Moving the boundary to exactly the oldest timestamp can skip events that share that millisecond.

Policy alerts

getPolicyAlerts returns alerts newest first, up to maxResults, with no cursor in the response. For the next page, send the timestampMs and uuid of the last alert you received as lastTimestampMs and lastUuid, keeping the same filters and window (afterTimestampMs, beforeTimestampMs). Stop when a page comes back empty or you reach the start of your window.

Choosing a page size

Larger pages mean fewer requests against your rate limit, but slower responses. For a full sync of a large organization, use the largest size the operation accepts, and keep the loop going until the last-page condition in the table above.