Skip to content

Reports & Analytics

Pull count and time-series analytics from the Rhombus API — people and vehicle counts, occupancy trends, line-crossing (threshold) counts, and CSV export.

On this page

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

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

scopestringbodyrequired

Aggregation level. One of ORG, LOCATION, DEVICE, or REGION. See the ReportScope table.

uuidstringbody

The location or device UUID that matches your scope. Omit for scope: "ORG" to report across the whole organization.

typesstring[]bodyrequired

One or more report types to count. See the ReportType table.

intervalstringbodyrequired

Bucket size for each data point. One of MINUTELY, QUARTERHOURLY, HOURLY, DAILY, WEEKLY, MONTHLY. See the ReportInterval table.

startTimeMsintegerbodyrequired

Start of the range, in epoch milliseconds.

endTimeMsintegerbodyrequired

End of the range, in epoch milliseconds.

timeZonestringbody

Optional IANA time zone (for example, America/New_York). Controls where interval bucket boundaries fall and populates dateLocal. Defaults to UTC when omitted.

Warning

The V2 endpoint accepts legacy startDate / endDate string fields, but these are deprecated. Use the epoch-millisecond startTimeMs / endTimeMs fields instead.

Response fields

timeSeriesDataPointsobject[]

One entry per interval bucket.

Show TimeSeriesDataPointV2Type
dateUtcstring
Bucket start expressed in UTC.
dateLocalstring
Bucket start expressed in the requested timeZone.
eventCountMapobject
Map of report type to count for this bucket, for example {"PEOPLE": 42, "VEHICLES": 7}.
reportingDevicesMapobject
Map of report type to the list of device UUIDs that contributed counts in this bucket.
Tip

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.

cURLbash
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 an occupancy dashboard, use getOccupancyCountsV2 for a bucketed occupancy trend over time, and chart getCountReportV2 with types: ["PEOPLE"] alongside it for foot traffic (see Build a count time-series).

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.

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

devicesstring[]body

One or more camera UUIDs to include in the counts.

startTimeMsintegerbody

Start of the range, in epoch milliseconds.

endTimeMsintegerbody

End of the range, in epoch milliseconds.

crossingObjectstringbody

The object class to count. Common values are HUMAN and VEHICLE. See the CrossingObject table.

dailyResetTimeMinuteintegerbody

Minute of the day (0–1439) at which the daily count resets, in the device's local time.

Response fields

countsobject[]
Show ThresholdCrossingCountType
countinteger
Number of crossings in this bucket.
timestampMsinteger
Bucket start in epoch milliseconds.

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.

Warning

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

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 — chart getOccupancyCountsV2 buckets to show occupancy through the day and compare it with earlier periods.
  • 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

Empty timeSeriesDataPoints or all-zero counts

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.

Buckets are offset from local time

Set the timeZone field to the relevant IANA zone (for example, America/Chicago). Without it, bucket boundaries and dateLocal fall on UTC.

Export request is rejected

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.

Export response looks like garbage JSON

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