Skip to content

Status & assets

The read endpoints behind the status page, asset pages, mobile Status screen, and the kiosk. Status, assets, units, and towers are public reads - no auth required; session or bearer also accepted. GET /api/contacts is the exception: it requires a session or the mobile bearer key (see Authentication).

The whole building in one call: property info, a status summary, and every asset with its uptime history. This is what the home page, the kiosk, and the mobile Status screen render.

{
"property": { "id": 1, "name": "Harborview Towers", "address": "", "timezone": "America/Toronto" },
"summary": { "total": 9, "operational": 6, "degraded": 1, "down": 1, "maintenance": 1 },
"assets": [
{
"id": 2,
"name": "Elevator A2",
"category": "elevator",
"towerName": "Tower A",
"status": "down",
"uptime30": "97.81",
"uptime90": "99.12",
"days": [
{ "date": "2026-03-15", "status": "operational" },
{ "date": "2026-03-16", "status": "maintenance" },
{ "date": "2026-03-17", "status": "down" }
],
"maintenanceUpcoming": [
{ "title": "Monthly inspection", "startsAt": "2026-06-16T10:00:00.000Z", "endsAt": "2026-06-16T12:00:00.000Z" }
]
}
]
}

Field notes:

  • summary - counts of assets currently in each status; total is the asset count.
  • status (per asset) - operational | degraded | down | maintenance.
  • uptime30 / uptime90 - uptime percentages over the trailing 30/90 days, two decimals. Derived from downtime incidents with overlapping intervals merged and maintenance windows excluded - the full math is in Reading uptime bars.
  • days - exactly 90 entries, one per calendar day in the property’s timezone, oldest first. status per day is the worst state that day: down | degraded | maintenance | operational (precedence in that order). Render as the slat bar.
  • maintenanceUpcoming - declared maintenance windows in the next 30 days for this asset (recurring windows appear as their expanded occurrences).

One asset in depth: the same asset fields and uptime data as /api/status, plus the asset’s incident history, most recent first.

{
"id": 2,
"name": "Elevator A2",
"category": "elevator",
"towerName": "Tower A",
"status": "down",
"description": "",
"uptime30": "97.81",
"uptime90": "99.12",
"days": [ { "date": "", "status": "" } ],
"maintenanceUpcoming": [ ],
"incidents": [
{
"id": 17,
"title": "Elevator A2 stuck on floor 7",
"severity": "critical",
"status": "in_progress",
"isDowntime": true,
"reporterName": "Anonymous resident",
"slaBreached": true,
"source": "web",
"createdAt": "2026-06-08T09:12:00.000Z",
"resolvedAt": null
}
]
}

For staff-authenticated callers the payload also includes the 365-day rollups used on asset detail and the Insights tab: cost365Cents (sum of repair costs across the asset’s incidents) and downtimeHours365 (from the uptime engine). Non-staff callers don’t receive cost data.

Incident field notes (these apply wherever incidents appear in the API):

  • status - open | acknowledged | in_progress | resolved | verified.
  • severity - low | medium | high | critical.
  • isDowntime - whether the incident counts against the asset’s uptime.
  • reporterName - display name; "Anonymous resident" when the reporter chose anonymity and the caller isn’t staff (staff see the real name).
  • slaBreached - true once the incident has exceeded its time-to-acknowledge target.
  • source - web | mobile | email.

The building directory, in display order. Requires auth - a session cookie or the mobile bearer key; an unauthenticated request returns 401. The directory carries vendor phone numbers, account IDs in notes, and the after-hours line, so it isn’t served to the anonymous public.

[
{
"id": 1,
"name": "M. Okafor",
"label": "Property Manager",
"phone": "+1 416 555 0181",
"email": "manager@harborview.example",
"notes": "Office hours Mon–Fri 9–5",
"sortOrder": 1
}
]

Picker data for report forms:

// GET /api/towers
[ { "id": 1, "name": "Tower A" }, { "id": 2, "name": "Tower B" } ]
// GET /api/units
[ { "id": 14, "towerId": 1, "number": "1204", "floor": 12 } ]

Serves uploaded incident photos through the active storage driver (local disk or S3/R2). Photo paths come from incident payloads; thumbnails use the .thumb.jpg variant generated at upload time.

The kiosk refreshes GET /api/status every 60 seconds; that’s a sensible ceiling for any dashboard-style consumer. Uptime percentages and day slats only change when incidents or maintenance windows do - for event-driven integrations, prefer webhooks (asset.status_changed, incident.*) over tight polling.