If you manage a mixed construction fleet with Samsara gateways, sooner or later you'll want to pull engine hours out of the Samsara API - to feed a utilization report, drive preventive maintenance schedules, or sync with your ERP. On paper it's one API call. In practice, engine hours are the single most misunderstood data point in the Samsara ecosystem, and getting them wrong quietly corrupts every downstream number you care about: utilization, idle time, cost per hour, and PM due dates.
We synchronize Samsara data for construction fleets every few minutes, around the clock. Here is what you actually need to know - and where the traps are.
Samsara splits your fleet into two object types with separate endpoints:
/fleet/vehicles/...) - on-road trucks, typically with a VG-series gateway plugged into the OBD port./fleet/equipment/...) - off-road machines (excavators, rollers, dozers), typically with an AG-series asset gateway wired to machine power or a J1939/CAT cable.The same physical yard can have both, and the two APIs return different stat types, paginate differently, and behave differently. Any integration that treats "the fleet" as one list will miss half of it.
For equipment, Samsara can report up to three parallel engine-hour readings for the same machine:
| Stat type | What it really is |
|---|---|
obdEngineSeconds | Engine runtime reported directly by the machine's on-board diagnostics. The gold standard - when available. |
gatewayJ1939EngineSeconds | Runtime approximated from how long the gateway receives power over a J1939/CAT cable. Good, but requires the right cable and a manual runtime offset to activate. |
gatewayEngineSeconds | Runtime approximated from how long the asset gateway itself has been powered. The weakest signal - and the one you'll get by default. |
Vehicles have their own pair: obdEngineSeconds (real) and syntheticEngineSeconds (Samsara's estimate, derived from ignition and voltage). The synthetic value can differ from the real meter by thousands of hours.
Your integration has to pick the right stream per machine - and machines differ. A machine with a healthy OBD connection should use obd; a machine wired with a CAT cable should use J1939; and if a gateway loses its data-bus connection, its gateway counter can freeze at an old value while still being reported with a fresh timestamp. If you naively take whatever comes back, two streams will interleave in your database, and the gap between them will show up as phantom operating hours. We have seen "165 hours per day" on a single machine from exactly this.
Samsara gives you three ways to read the same stat, and they do not agree:
/stats) returns each asset's "last known" value. Convenient - but it only includes stat types Samsara considers current, so a machine's best meter (say, J1939) can be silently absent while a stale one is present. Worse, cached values can be re-stamped with fresh timestamps, so stale data looks live./stats/history) returns readings over a time window - but deduplicated to value changes. A counter that's been frozen for months appears as a single innocent data point, which masks exactly the problem you'd want to detect./stats/feed) is a cursor-based stream of new datapoints since your last call. This is the one you want for continuous sync: it carries all stat types reliably, doesn't re-send what you've seen, and scales. But you must persist cursors correctly, handle cursor expiry, and still keep a snapshot pass as a safety net for machines that haven't reported recently.Most homegrown integrations start with the snapshot because it's the obvious endpoint - and inherit all its blind spots.
The same API means different things depending on what's bolted to the machine:
Engine hours drive daily utilization math (typically max reading minus min reading per day). That means one bad reading in a day corrupts that day. Polling hourly with the snapshot endpoint gives you ~24 chances a day to ingest a stale value; a cursor-based feed with per-machine stream selection and a monotonicity check (a real meter never runs backwards) gives you almost none. The difference isn't the API - it's the validation layer you build around it.
If you're building this in-house, budget for:
That's a real engineering project, and the maintenance never ends: hardware changes, machines migrate between telematics providers, and edge cases arrive one fleet at a time.
This is the part where we're biased, but for good reason: CLUE synchronizes Samsara alongside 60+ other OEM and telematics feeds, with all of the above built in - per-machine stream selection, frozen-counter rejection, feed-based sync, and automatic repair when a provider sends bad data. Your team sees one clean utilization number per machine per day, and your PM schedules trigger on real hours.
If your fleet runs on Samsara (or Samsara plus anything else), we'd love to show you what clean, cross-OEM engine-hour data looks like in practice.