Skip to main content
The Ops Playbook

Auto-Releasing Ghost-Booked Meeting Rooms Before Complaints Start

Combine Microsoft Graph webhooks and occupancy sensors to auto-decline unclaimed meeting room bookings before facilities ever raises a ticket.

Auto-Releasing Ghost-Booked Meeting Rooms Before Complaints Start
Sarah LiangSarah Liang9 min readTier L250 min

This playbook covers

Share

#Current Method

In most estates the room mailbox calendar and the physical room are only loosely connected. A booking exists in Exchange Online, but nothing checks whether the organiser or any attendee actually arrived. When nobody turns up, the room sits reserved and visibly “busy” on panel displays while walk-up staff are turned away. The usual detection method is a human one: a colleague notices the empty room, checks the console, and eventually raises a facilities ticket. By the time that happens the meeting slot is long gone and the complaint is about a process failure, not a technical one.

This creates three material problems worth naming rather than assuming away. First, evidence is late: the organisation only learns a room was wasted after the fact, from a complaint rather than a signal. Second, remediation is manual: someone with calendar delegate rights has to open Outlook or the Exchange admin centre and cancel the booking by hand. Third, there is no consistent grace period policy — different people apply different judgement about how long is “too long” before a room counts as abandoned, so behaviour varies by building and by who happens to notice.

#Improved Workflow

The improved workflow replaces human noticing with two correlated signals and a single decision point. The first signal is the calendar itself, delivered as a Microsoft Graph change notification rather than a polling query, so the platform learns about a booking the moment it is created, changed or approaching its start time. The second signal is room occupancy, sourced from whatever sensor or managed console check-in mechanism is already deployed in the building. Neither signal alone is trustworthy: calendar state cannot tell you whether anyone is physically present, and occupancy sensors cannot tell you whether a booking exists to release. Combining them in a decision engine lets the system distinguish a genuinely abandoned booking from a meeting that simply started without anyone touching the console.

Each stage exists for a specific reason. The webhook subscription exists so the platform reacts to calendar events instead of polling the Graph API on a timer, which conserves API quota and reduces detection latency. The occupancy signal exists so the system does not auto-decline a real meeting purely because nobody pressed a button on the console — some rooms are used by people who never touch it. The decision engine exists to apply a single, auditable grace period policy instead of inconsistent human judgement. The notification step exists so the organiser is never surprised by a cancelled booking with no explanation and no path back to a room.

#Implementation

#
Prerequisites and Permissions

Before building anything, confirm three things are true for the estate in scope: room mailboxes exist as a distinct object type in Exchange Online, the rooms already have managed consoles or an occupancy sensor feed of some kind, and there is an application registration process available for a Graph app that will be scoped to those mailboxes only. Assumption for human review: this playbook assumes Teams Rooms managed consoles or an equivalent sensor feed are already deployed; it does not cover procuring or installing that hardware.

#
Architecture at a Glance

At a high level, calendar change notifications and occupancy events flow into a decision engine, which either leaves the booking alone or auto-declines it and notifies the organiser. The diagram below shows that flow.

Rendering diagram...

#
Step 1: Configure the native release timer on managed consoles

Where Teams Rooms managed consoles are present, start with the console’s own unclaimed-meeting release behaviour before adding external logic. This gives a baseline safety net even if the webhook pipeline is temporarily down. Assumption for human review: the exact release timer duration and its administration path vary by console firmware and tenant policy version, so confirm the current setting against your fleet’s managed console policy rather than a fixed number.

#
Step 2: Scope the Graph app to room mailboxes only

Register a dedicated Graph application and restrict it with an application access policy so its permissions apply only to a security group containing room mailboxes — never tenant-wide mailbox access. This is a least-privilege control, not an optional hardening step: an unscoped application credential with calendar read/write across all mailboxes is a disproportionate blast radius for a room-release feature.

#
Step 3: Stand up the occupancy webhook receiver

Deploy a small, internet-reachable receiver endpoint that accepts occupancy or check-in events from the sensor or console fleet. Treat this endpoint as a trust boundary: authenticate the sender, validate payload shape, and reject anything that does not match the expected schema before it reaches the decision engine.

#
Step 4: Subscribe to calendar change notifications

Create a Microsoft Graph subscription against each room mailbox calendar so the platform is notified of relevant changes instead of polling. Graph calendar subscriptions expire and must be renewed before the expiry window closes; treat renewal as a scheduled job with its own monitoring, not a fire-and-forget setup step.

#
Step 5: Deploy the decision engine

The decision engine correlates the two signals against a configured grace period: if a booking has started and no occupancy signal arrives within that window, it triggers a decline; if occupancy is confirmed, the booking is left untouched. Log every decision with the evidence that produced it, since this log is what you will use for validation and for defending or reversing individual decisions later.

1on calendar_event(booking):
2    start_grace_timer(booking, grace_period_minutes)
3
4on occupancy_event(room, signal):
5    if booking_active(room):
6        cancel_grace_timer(room)
7        record_evidence(room, "occupied", signal)
8
9on grace_timer_expired(booking):
10    if not occupancy_confirmed(booking):
11        decline_booking(booking)
12        notify_organiser(booking, rebook_link=true)
13        record_evidence(booking, "auto_declined", reason="no_checkin")

#
Step 6: Watch the subscription renewal job

Because Graph calendar subscriptions have a finite lifetime, the renewal job is a single point of failure for the whole pipeline: if it silently stops, the system reverts to no detection at all with no visible error until someone notices bookings are no longer being released. Alert on renewal failures, not just on subscription expiry.

#
Step 7: Notify the organiser and offer a rebook path

Every auto-decline should generate a message to the organiser explaining what happened and why, with a direct link or instruction to rebook. Silent auto-decline without explanation converts a process improvement into a trust problem, and undermines adoption of the whole system.

#Guardrails

Scope the Graph application to room mailboxes only, using an application access policy rather than relying on documentation to enforce the boundary. Set a grace period long enough to tolerate normal late arrivals; a value that is too short will decline legitimate meetings and generate exactly the complaints this playbook is meant to prevent. Keep a manual override path so a facilities administrator or room owner can pause auto-decline for a specific room without redeploying the whole pipeline — recurring VIP bookings and irregular-use rooms are the most likely places this will be needed. Rate-limit and de-duplicate webhook deliveries, since Graph notification delivery is not guaranteed to be exactly-once and duplicate events must not produce duplicate declines or duplicate organiser notifications.

#Validation

Before wide rollout, validate the pipeline on a small pilot group of rooms and confirm each of the following produces the expected evidence: a new subscription returns a success response with a visible expiry timestamp; the webhook receiver logs an inbound event within the expected renewal window; an intentionally unclaimed test booking is auto-declined and the decision log shows the evidence that triggered it; the organiser receives a notification with a working rebook link; and a genuinely occupied test booking is left untouched with an occupancy-confirmed log entry. Only expand scope once these five checks pass consistently across the pilot rooms over more than one day, since single-day results can hide renewal-timing issues.

#Common Mistakes

The most consequential mistake is granting the Graph application tenant-wide calendar permissions because it was faster than configuring an access policy scoped to the room mailbox group; this converts a low-risk automation into a high-privilege credential. A second mistake is treating the subscription renewal job as a one-off setup task rather than a monitored scheduled job, which causes detection to silently stop working weeks later. A third is setting the grace period from a generic default rather than observing actual arrival patterns for the estate, which produces either too many false declines or a system that never triggers at all. A fourth is auto-declining without notifying the organiser, which trades a facilities ticket for a help desk ticket instead of removing the friction.

#Recovery

If the decision engine incorrectly declines a live meeting, the immediate correction is to restore the booking using delegate calendar access on the room mailbox and notify the affected organiser directly rather than waiting for them to notice. If the subscription renewal job has failed, resubscribe manually against the affected room mailboxes and only then investigate why the scheduled renewal did not run, since re-establishing detection takes priority over root-causing the scheduler. If the application access policy scope was found to be too broad, narrow it immediately and treat the interim period as requiring a permissions review, even if no misuse is suspected. Keep the native console release timer active throughout rollout so that a pipeline outage degrades to the existing baseline behaviour rather than to no protection at all.

#Measurable Outcome

Establish a baseline before deployment: the number of facilities tickets per month related to unreleased or ghost-booked rooms, and the average time between a room becoming vacant and the booking being released. The success signal is a reduction in both figures for the pilot rooms, measured by comparing ticket volume and decision-log timestamps over a minimum four-week window against the pre-deployment baseline. Review the grace period threshold at the same cadence, adjusting it only when the false-decline rate (auto-declines later confirmed as mistaken) is tracked alongside the reduction in tickets, so a lower ticket count is not achieved by simply declining too aggressively.

#Checklist

  • Confirm room mailboxes and occupancy signal sources exist for every room in scope before building anything.
  • Scope the Graph application to room mailboxes only via an application access policy.
  • Deploy and authenticate the occupancy webhook receiver as a trust boundary, not an open endpoint.
  • Create calendar change subscriptions and put subscription renewal under active monitoring.
  • Set an evidence-based grace period and log every decision with its supporting signal.
  • Confirm organiser notifications and rebook links work before wide rollout.
  • Keep the native console release timer active as a fallback throughout deployment.
  • Compare ticket volume and false-decline rate against baseline after at least four weeks before adjusting thresholds.
Sarah Liang

Sarah Liang

Ops Playbook Architect

Sarah Liang is a Cloud Solutions Architect designing highly available, globally distributed applications. With deep expertise across multi-cloud topologies and serverless paradigms, she partners with enterprise teams to migrate monolithic architectures into scalable, cost-efficient microservices with rigorous performance Service Level Objectives.

Published
View Profile
Reader Interaction

Comments

Add a thoughtful note on Auto-Releasing Ghost-Booked Meeting Rooms Before Complaints Start. Comments are checked for spam and held for moderation before appearing.

Loading comments...
Comment submission is disabled until Cloudflare Turnstile keys are configured.

Discover more

Learn More About KBY

Was this useful?

Operate smarter, with fewer recurring tickets.

Receive new operational playbooks, incident-prevention guidance, automation scripts and recovery runbooks.