Skip to main content

Overview

The Rhombus Report Webservice turns detections from your cameras into aggregated, time-bucketed analytics. Instead of iterating over individual events, you request a count report for a time range and interval, and Rhombus returns one data point per bucket with a per-type count. Through the API, you can:
  • Build count time-series for people, vehicles, motion, faces, and other detection types across an org, location, or single device
  • Track people counts and occupancy with the latest readings and bucketed occupancy trends
  • Measure line-crossing (threshold) counts for humans or vehicles that cross a configured line
  • Export report data as CSV for spreadsheets, BI tools, and compliance reporting
A few conventions apply across this API:
  • Timestamps are epoch milliseconds on the V2, occupancy, and threshold endpoints (startTimeMs / endTimeMs). The legacy v1 getCountReport uses "YYYY-MM-DD" date strings instead.
  • Reports are described by three enums — a report type (what to count), an interval (bucket size), and a scope (org, location, or device). See the reference tables below.
  • There is no “list report types” endpoint. The available types are fixed and documented in the ReportType table.

Prerequisites

Before you begin, make sure you have:
  • A Rhombus API key with report permissions (generated in the Rhombus Console under Settings > API)
  • At least one camera deployed and reporting the analytics you want to query (for example, a camera running people counting or LPR)
  • The UUID of the org, location, or device you want to scope the report to
  • For CSV export and audit/diagnostic feeds: the REPORT_ADMINISTRATION permission on the API key
All requests are POST, send a JSON body, and use the base URL https://api2.rhombussystems.com with these headers:
x-auth-scheme: api-token
x-auth-apikey: YOUR_API_KEY
Content-Type: application/json

Build a count time-series

getCountReportV2 is the primary reporting endpoint. Supply a time range in epoch milliseconds, an interval, a scope, and one or more report types. Rhombus returns one data point per interval bucket, each carrying an eventCountMap keyed by report type. This example pulls hourly people and vehicle counts for a single location over the last 24 hours.
import requests
import time

headers = {
    "x-auth-scheme": "api-token",
    "x-auth-apikey": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

now_ms = int(time.time() * 1000)
one_day_ago_ms = now_ms - (24 * 60 * 60 * 1000)

response = requests.post(
    "https://api2.rhombussystems.com/api/report/getCountReportV2",
    headers=headers,
    json={
        "scope": "LOCATION",
        "uuid": "YOUR_LOCATION_UUID",
        "types": ["PEOPLE", "VEHICLES"],
        "interval": "HOURLY",
        "startTimeMs": one_day_ago_ms,
        "endTimeMs": now_ms,
        "timeZone": "America/Los_Angeles"
    }
)

data = response.json()
for point in data.get("timeSeriesDataPoints", []):
    counts = point.get("eventCountMap", {})
    print(f"{point.get('dateLocal')}: "
          f"people={counts.get('PEOPLE', 0)}, "
          f"vehicles={counts.get('VEHICLES', 0)}")

Request fields

scope
string
required
Aggregation level. One of ORG, LOCATION, DEVICE, or REGION. See the ReportScope table.
uuid
string
The location or device UUID that matches your scope. Omit for scope: "ORG" to report across the whole organization.
types
string[]
required
One or more report types to count. See the ReportType table.
interval
string
required
Bucket size for each data point. One of MINUTELY, QUARTERHOURLY, HOURLY, DAILY, WEEKLY, MONTHLY. See the ReportInterval table.
startTimeMs
integer
required
Start of the range, in epoch milliseconds.
endTimeMs
integer
required
End of the range, in epoch milliseconds.
timeZone
string
Optional IANA time zone (for example, America/New_York). Controls where interval bucket boundaries fall and populates dateLocal. Defaults to UTC when omitted.
The V2 endpoint accepts legacy startDate / endDate string fields, but these are deprecated. Use the epoch-millisecond startTimeMs / endTimeMs fields instead.

Response fields

timeSeriesDataPoints
object[]
One entry per interval bucket.
Need a single total instead of a bucketed series? Call /api/report/getSummaryCountReport with the same startTimeMs, endTimeMs, interval, scope, and a single type.

Legacy date-string reports

The v1 /api/report/getCountReport endpoint predates epoch-millisecond timestamps. It takes startDate and endDate as "YYYY-MM-DD" strings and a single type rather than a types array. Prefer getCountReportV2 for new integrations; use v1 only if you already depend on its date-string behavior.
cURL
curl -X POST https://api2.rhombussystems.com/api/report/getCountReport \
  -H "Content-Type: application/json" \
  -H "x-auth-scheme: api-token" \
  -H "x-auth-apikey: YOUR_API_KEY" \
  -d '{
    "scope": "LOCATION",
    "uuid": "YOUR_LOCATION_UUID",
    "type": "PEOPLE",
    "interval": "DAILY",
    "startDate": "2024-01-01",
    "endDate": "2024-01-31"
  }'

Build a people-count and occupancy dashboard

For a live dashboard, combine two endpoints: getMostRecentPeopleCountEvents for the latest readings from a camera, and getOccupancyCountsV2 for a bucketed occupancy trend over time.

Latest people-count readings

import requests

headers = {
    "x-auth-scheme": "api-token",
    "x-auth-apikey": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

response = requests.post(
    "https://api2.rhombussystems.com/api/report/getMostRecentPeopleCountEvents",
    headers=headers,
    json={
        "deviceUuid": "YOUR_CAMERA_UUID",
        "numMostRecent": 10
    }
)

data = response.json()
for event in data.get("events", []):
    print(f"[{event.get('eventTimestamp')}] people={event.get('peopleCount')}")
Each entry in events is a people-count reading:
events
object[]

Occupancy trend over time

getOccupancyCountsV2 returns bucketed occupancy for a device across a time range, using the same interval model as count reports.
import requests
import time

headers = {
    "x-auth-scheme": "api-token",
    "x-auth-apikey": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

now_ms = int(time.time() * 1000)
one_day_ago_ms = now_ms - (24 * 60 * 60 * 1000)

response = requests.post(
    "https://api2.rhombussystems.com/api/report/getOccupancyCountsV2",
    headers=headers,
    json={
        "deviceUuid": "YOUR_CAMERA_UUID",
        "startTimeMs": one_day_ago_ms,
        "endTimeMs": now_ms,
        "interval": "HOURLY"
    }
)

data = response.json()
for point in data.get("timeSeriesDataPoints", []):
    print(f"{point.get('dateLocal')}: {point.get('eventCountMap')}")
The response timeSeriesDataPoints carry the same dateUtc, dateLocal, eventCountMap, and reportingDevicesMap fields as count reports, plus a timestampMs (bucket start in epoch milliseconds) and an approximateTimestampMsMap.
This occupancy report is derived from camera analytics via the Report Webservice. It is distinct from the Occupancy Webservice (/api/occupancy/*), which reads physical BLE and motion sensors — a separate product.

Count line crossings (threshold counts)

When a camera has a crossing line configured, Rhombus counts objects that cross it. getThresholdCrossingCounts returns those counts bucketed over time for one or more devices, filtered to a single object class. The dailyResetTimeMinute field sets the minute of the day (0–1439, in the device’s local time) at which the running daily count resets — useful for aligning counts to a business day rather than midnight.
import requests
import time

headers = {
    "x-auth-scheme": "api-token",
    "x-auth-apikey": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

now_ms = int(time.time() * 1000)
one_week_ago_ms = now_ms - (7 * 24 * 60 * 60 * 1000)

response = requests.post(
    "https://api2.rhombussystems.com/api/report/getThresholdCrossingCounts",
    headers=headers,
    json={
        "devices": ["YOUR_CAMERA_UUID"],
        "startTimeMs": one_week_ago_ms,
        "endTimeMs": now_ms,
        "crossingObject": "HUMAN",
        "dailyResetTimeMinute": 0
    }
)

data = response.json()
for entry in data.get("counts", []):
    print(f"[{entry.get('timestampMs')}] crossings={entry.get('count')}")

Request fields

devices
string[]
One or more camera UUIDs to include in the counts.
startTimeMs
integer
Start of the range, in epoch milliseconds.
endTimeMs
integer
End of the range, in epoch milliseconds.
crossingObject
string
The object class to count. Common values are HUMAN and VEHICLE. See the CrossingObject table.
dailyResetTimeMinute
integer
Minute of the day (0–1439) at which the daily count resets, in the device’s local time.

Response fields

counts
object[]

Export report data as CSV

The Export Webservice streams report data as CSV (text/csv) rather than JSON. There is no PDF export — CSV is the only export format.
Export endpoints (and the audit/diagnostic feeds) require the REPORT_ADMINISTRATION permission on your API key. Without it, these calls are rejected.
/api/export/countReports mirrors the count report parameters but returns a CSV stream. Note that export takes a single type field, not a types array, and both startTimeMs and endTimeMs are required.
import requests
import time

headers = {
    "x-auth-scheme": "api-token",
    "x-auth-apikey": "YOUR_API_KEY",
    "Content-Type": "application/json"
}

now_ms = int(time.time() * 1000)
thirty_days_ago_ms = now_ms - (30 * 24 * 60 * 60 * 1000)

response = requests.post(
    "https://api2.rhombussystems.com/api/export/countReports",
    headers=headers,
    json={
        "scope": "LOCATION",
        "uuidList": ["YOUR_LOCATION_UUID"],
        "type": "PEOPLE",
        "interval": "DAILY",
        "startTimeMs": thirty_days_ago_ms,
        "endTimeMs": now_ms,
        "timeZone": "America/Los_Angeles"
    }
)

# Response is CSV text, not JSON
with open("people_count_report.csv", "w") as f:
    f.write(response.text)
print("Exported report to people_count_report.csv")
Because the response body is CSV, read it as text (response.text / .text()) or write it straight to a file with the -o flag in cURL. Do not attempt to parse it as JSON.
To export raw people-count readings instead of aggregated reports, use /api/export/peopleCountEvents with a startInterval and endInterval (epoch milliseconds). It returns CSV the same way.

Enum reference

Reports are described by a small set of fixed enums. There is no endpoint that lists these at runtime — the values below are the complete set.

ReportType

Values accepted by the types array (V2) and single type field (v1 and export).
ValueCounts
CROWDCrowd-density detections
PEOPLEPeople detections / people counting
FACESFace detections
MOTIONMotion events
BANDWIDTHDevice bandwidth usage
VEHICLESVehicle detections
LICENSEPLATESLicense-plate reads
ALERTSAlert / policy events
AM_VERIFICATIONAlarm-monitoring verifications
DWELLDwell-time detections

ReportInterval

Bucket size for each data point.
ValueBucket
MINUTELYPer minute
QUARTERHOURLYPer 15 minutes
HOURLYPer hour
DAILYPer day
WEEKLYPer week
MONTHLYPer month

ReportScope

Aggregation level for a count report. Provide a matching uuid for LOCATION, DEVICE, or REGION; omit it for ORG.
ValueAggregates over
ORGThe entire organization
LOCATIONA single location
DEVICEA single device
REGIONA configured region

CrossingObject

Object class for getThresholdCrossingCounts.
ValueObject
HUMANPeople
VEHICLEVehicles
FACEFaces
LPRLicense plates
POSEPose detections
CLIP_EMBEDVisual-embedding matches
UNKNOWNUnclassified

Use cases

  • Foot-traffic dashboards — chart hourly or daily PEOPLE counts per location with getCountReportV2 to compare stores or track trends over time.
  • Occupancy monitoring — combine getMostRecentPeopleCountEvents (live reading) with getOccupancyCountsV2 (trend) to show current and historical occupancy on one screen.
  • Entrance and lane counting — use getThresholdCrossingCounts with crossingObject: "HUMAN" or "VEHICLE" to count people through a doorway or cars through a lane.
  • Scheduled reporting — run /api/export/countReports on a cron and drop the CSV into a BI tool or data warehouse for weekly and monthly reporting.

Advanced: AI Scene Query analytics

Rhombus also offers Scene Query, an AI feature that counts custom, natural-language-defined events (for example, “forklifts without a spotter”). Scene Query is configured through the /api/scenequery/* endpoints and reported via /api/report/getCustomEventsReport. It is a distinct, licensed capability rather than part of the core reporting workflow above — treat it as an optional extension when standard report types don’t capture what you need to measure.

Troubleshooting

Confirm that the device actually produces the analytic you requested — a camera without people counting enabled returns no PEOPLE data. Also verify your time range is in epoch milliseconds (not seconds) and that the scope/uuid pair is correct.
Set the timeZone field to the relevant IANA zone (for example, America/Chicago). Without it, bucket boundaries and dateLocal fall on UTC.
CSV export requires the REPORT_ADMINISTRATION permission. Check the API key’s permissions in the Rhombus Console, and remember the export body uses a single type field rather than the types array used by getCountReportV2.
The export endpoints return text/csv, not JSON. Read the response as text or write it to a file rather than calling .json().

Next Steps

Faces & People Counting

Enroll people, query face events, and dig deeper into people-counting analytics

LPR & Vehicles

Query license-plate reads and vehicle detections that feed the vehicle report types

API Reference

Explore complete request and response schemas for every report and export endpoint
Last modified on July 8, 2026