analytics

Get Delivery Latency

How long alarms take to reach an operator — the Analytics → System Health delivery-latency panel.

Owner + support through the SAME dependency /system-health uses, and for the same reason: every number here is a cross-tenant fleet aggregate, and the camera rows name cameras, sites and parents under every customer. There is deliberately no scoped variant — a narrowed one would leak fleet facts by construction — so there is no parent_id/site_id parameter and nothing for ensure_analytics_filter_in_scope to check.

window IS A TWO-VALUE ENUM, NOT AN hours INT. The cost profile is tuned for exactly these two windows and the ~5-minute cache is keyed on them, so a free int would make the cache's key space unbounded and would invite arbitrary scans of the highest-insert table in the system. Anything else is a 422 rather than an expensive 200.

get/analytics/delivery-latency

Request

  • Base URL
    https://api.verdun.ai (the document declares no server; this is the origin it was published from)
  • URL
    https://api.verdun.ai/analytics/delivery-latency
  • Auth
    HTTP bearer

Query parameters

window'24h' | '7d'

Which window: the latest 24 clock-hour buckets, or the latest 168 (7 days). The last bucket is the hour IN PROGRESS and is partial, so the span is 23 (or 167) whole hours plus the elapsed part of the current hour — the response publishes the exact bounds as window_start/window_end.

Response

Successful Response

generated_atstring date-time required

When this payload was computed. Served from a ~5-minute per-process cache, so two consecutive polls can land on different API tasks and see slightly different values — key any freshness banner off your own fetch time, not off this alone.

cache_age_secondsinteger required

How old the served payload is, in seconds. 0 means this request computed it.

window_hoursinteger required

How many CLOCK-HOUR BUCKETS the window is: 24 or 168. hourly and every hourly_p50_s have exactly this many entries. It is a bucket count, NOT the elapsed span — the last bucket is the hour in progress and is partial, so the real span is window_end - window_start = 23 (or 167) whole hours plus the elapsed part of the current hour. A '24h' window at 18:05 therefore does NOT include yesterday 18:05-19:00.

window_startstring date-time required

Inclusive start of the window, in UTC — the top of the oldest bucket, and the same value as hourly[0].hour. Published so a consumer can state the span it was actually given rather than inferring a rolling window from window_hours.

window_endstring date-time required

Exclusive end of the window, in UTC — generated_at, i.e. mid-hour. Truncated to the hour it equals hourly[-1].hour, the partial bucket in progress.

min_camera_eventsinteger required

Minimum eligible alarms for a camera to appear in cameras at all. Published so the UI labels the rule the server actually applied instead of restating a constant that can drift.

top_camerasinteger required

Maximum number of camera rows returned. A BOUND, NOT A PAGE SIZE — there is no second page, and the value is deliberately set well above the monitored fleet so cameras is in practice the complete ranked list. Published, like min_camera_events, so the UI labels the rule the server actually applied instead of restating a constant that can drift.

notesstring[]

Server-authored caveats, with this window's counts already interpolated. Render them verbatim wherever these numbers are shown — several of them are the difference between reading the median correctly and misreading it.

Example response

{
  "cache_age_seconds": 137,
  "window_hours": 24,
  "window_start": "2026-09-15T19:00:00+00:00",
  "window_end": "2026-09-16T18:05:11.204000+00:00",
  "fleet": {
    "events": 4812,
    "cameras": 61,
    "motion_to_queue": {
      "p50_s": 18.4,
      "p90_s": 31.7
    },
    "motion_to_clip": {
      "p50_s": 18.4,
      "p90_s": 31.7
    },
    "clip_to_queue": {
      "p50_s": 18.4,
      "p90_s": 31.7
    },
    "band_7d": {
      "p50_s": 17.9,
      "p90_s": 21.3,
      "days": 7
    },
    "over_60s": 38,
    "failsafe_sentinels": 4,
    "early_broadcast_share_pct": 71.3,
    "clock_suspect_cameras": 2,
    "clock_suspect_events": 57,
    "missing_occurred_at": 11
  },
  "hourly": [
    {
      "events": 210,
      "p50_s": 17.8,
      "p90_s": 29.9
    }
  ],
  "cameras": [
    {
      "camera_id": "2b1d3f2e-6e78-4d9b-93d6-3c1f9e40a1d4",
      "camera_label": "23 - NE Lot",
      "site_id": "9f2c0f31-5d0a-4a6e-8b41-2f7a1d6c0e55",
      "site_name": "Imperial SE",
      "account_id": "c41b7a90-3e2d-4f18-9a55-70b6d2c3f8ab",
      "account_name": "Northwind Retail",
      "parent_id": "3a7e5c12-8b44-4d21-9e0f-6c5b1a2d3e47",
      "parent_name": "Pioneer Security",
      "events": 184,
      "p50_s": 24.1,
      "p90_s": 58.9,
      "clip_p50_s": 22.6,
      "queue_p50_s": 1.1,
      "motion_clock": "camera",
      "over_60s": 21,
      "clock_suspect_events": 3
    }
  ],
  "min_camera_events": 10,
  "top_cameras": 200
}

Changes

No recorded changes to this operation across all 2 revisions of this API.