API reference
Property Twin
The counts behind the Property tab: who is on property, what is open, what has been earned today.
The digital twin is the Property tab in Hotel Operator: counts and a live stream of events. No floor plans, no predictions. This route supplies the counts. The stream beside them comes from GET /v1/activity.
Every number is computed on read against the property's current calendar day in America/Nassau. Nothing here is cached or precomputed.
GET /v1/property/summary
One payload holding every count the Property tab renders.
Auth: unauthenticated in this build.
Request
GET /v1/property/summary
GET /v1/property/summary
No path params, no query params, no body.
Response
JSON
{
"on_property": { "total": 1, "consented": 1 },
"arrivals_today": 0,
"departures_today": 0,
"requests": {
"open": 1,
"overdue": 1,
"queues": [
{ "queue_id": "guest_services", "label": "Guest Services", "open": 1, "overdue": 1 }
]
},
"offers": { "open": 0, "accepted_today": 0, "revenue_today_usd": 0 },
"groups": { "groups": 0, "largest": 0 },
"recovery": { "incidents_today": 0, "gestures_sent_today": 0 },
"revenue_today_usd": 75
}
| Field | Type | Meaning |
|---|---|---|
on_property.total | number | Live-origin stays whose arrival is on or before today and whose departure is on or after it. |
on_property.consented | number | The subset of those with analytics_consent = 1. |
arrivals_today | number | Live-origin stays arriving today. |
departures_today | number | Live-origin stays departing today. |
requests.open | number | Sum of the per-queue open counts. |
requests.overdue | number | Sum of the per-queue overdue counts. |
requests.queues[] | array | One entry per row in the queues table, each with queue_id, label, open, overdue. |
offers.open | number | Offers with status open whose expires_at is still in the future. |
offers.accepted_today | number | Offer instances accepted today. |
offers.revenue_today_usd | number | Sum of value_usd on those instances. |
groups.groups | number | Live groups, from the same computation as GET /v1/groups/summary. |
groups.largest | number | Biggest live group's active member count. |
recovery.incidents_today | number | friction_detected events from source make_it_right today. |
recovery.gestures_sent_today | number | recovery_sent events from source make_it_right today. |
revenue_today_usd | number | Sum of value_usd across bookings created today, from every path (requests, offers, group activities). |
A request is overdue when it is still open and was created strictly earlier than now minus its queue's sla_minutes. A request created exactly at the cutoff is not yet overdue. Each queue carries its own SLA from the config: 15 minutes for Dining, 20 for Guest Services and Bell Desk, 30 for Housekeeping.
With an empty database every block returns zeros and requests.queues is an empty array.
Errors
None. The route always returns 200.
Notes
offers.revenue_today_usdandrevenue_today_usdare different numbers on purpose. The first counts only accepted offer instances, the second counts every booking written today.- The recovery block reads only events whose
sourceismake_it_right. Core events with the same names never count toward it. - Dates are compared on their first ten characters, so vendor rows carrying
2026-09-10 00:00:00line up with fixture rows carrying2026-09-10. - The Property tab pairs this route with
GET /v1/activity. Counts here, sentences there. Seeactivity-and-events.md.