> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Hot-desking: shared desk phones with sign-in and reservations

> Walk through the full Voice → Hot-desking workflow — the sign-in/sign-out binding for shared desk phones, the advance reservation calendar, conflict prevention, and a rotating-shift call-center setup.

The **Voice → Hot-desking** dashboard page runs shared desk phones as a pool instead of fixed assignments: an agent signs in to a physical phone, it becomes their extension for the shift, and it returns to the pool when they sign out. On top of walk-up sign-in, a reservation calendar lets agents book a specific desk for a future window and blocks anyone else from taking it.

Retail floors, clinics, and hybrid offices typically have more agents than desks. Hot-desking means you provision one shared SIP credential per phone, not one per person, while every call still routes personally. This guide walks the whole lifecycle end to end, from first sign-in through advance reservations to the admin revoke.

Your control surface is fully **tenant-owned**: who is allowed to sign in lives in your member roles, queue behavior lives in your queue configuration, and the roster model below is an example you adapt — nothing here is gated by the platform.

## 1. The concept: transient user-to-device binding

A session binds **one user to one device** for a bounded time. Enforcement is symmetric: one active session per device, and one per user, so the phone is never double-bound and the agent is never sitting at two desks at once. The binding is transient — it follows the person, not the hardware.

**What follows the user** (attached to the device for the session):

* Extension number and caller ID — outbound calls from the phone present the agent's identity while signed in, and inbound calls to the agent's extension ring that phone.
* Voicemail delivery — the agent's mailbox applies for the session.
* Queue membership — the agent is reachable at this device for queue calls.

**What stays with the device** (never moves):

* The SIP registration — the phone keeps its own shared-pool credential (`acme-shared-5F-2`-style), provisioned once under **Voice → SIP credentials**.
* The shared-pool inbound rule — while signed out, inbound to the pool follows the device's default inbound rule, so a phone never dangles without routing. See [Hot-desking](/voice/hot-desking) for device provisioning detail.

Think of it as the phone borrowing the agent's identity and lending its own hardware back when the session ends.

## 2. The sign-in / sign-out lifecycle

The session moves through a small state machine:

```
         sign in                      sign out / displace / revoke / expire
shared pool ──────────► active ──────────────────────────────────────► released
                       ▲ │
                       │ └─ idempotent re-sign-in to the SAME device
               sign someone NEW in ─► their old session releases atomically
```

The release column of the session ledger records **how** it ended — `signed_out`, `displaced_by_new_session`, `revoked`, or expiry — which is what the admin list on **Voice → Hot-desking** shows.

**Sign in** (`POST /api/v1/voice/hot-desking/sign-in`):

* The agent opens **Voice → Hot-desking**, enters the device's SIP username (label the physical phone with this), and an optional friendly label such as `Floor 5 — Desk 2`.
* An optional end-of-shift `expiresAt` (up to 24h ahead) releases the session automatically — a backstop, not a guarantee.
* If either party has an active session, the new sign-in **displaces** it atomically: signing in to a phone in use signs the prior agent out; signing in at a second phone signs the agent out of the first.
* Re-signing to the same device is a no-op — the existing session is re-confirmed rather than duplicated (the API responds `200` instead of `201`).

**Sign out** (`POST /api/v1/voice/hot-desking/sign-out`) is **idempotent** — a second sign-out does not error; it reports when the session actually ended (with the release reason), so a double-tapped button is harmless.

**Revoke** (`POST /api/v1/voice/hot-desking/:id/revoke`) — owner/admin force-release. Use it for a terminated employee or a lost device from the same dashboard page.

If two sign-ins collide for the same device or user, one wins and the other is asked to retry with a `409` — the winner holds the device.

## 3. The reservation calendar

Beside the walk-up board, **Voice → Hot-desking** has a booking calendar that reserves a specific desk for a future window — the model Cisco UCM, RingCentral, and 8x8 all ship on top of extension mobility. The calendar enforces single-booking: two overlapping windows for the same device can never both exist.

**Recurring shifts vs ad-hoc visits.** There is no first-class "recurring reservation" object — a **recurring roster needs one reservation per shift window**: either duplicate the booking on the dashboard each week, or submit one API call per shift (a loop in your scheduling integration) with the same `deviceSipUsername`. An **ad-hoc visit** is just a single one-off window — book it the same way. Either way you get the same conflict safety: the 409 double-booking rejection guarantees only one reservation holds the desk across any time slot.

**Book** (`POST /api/v1/voice/hoteling/reservations`) with `deviceSipUsername`, `startsAt`, `endsAt` (ISO-8601), and an optional `notes`. Limits: window ≤ 24 hours, start ≤ 90 days ahead, end must be after start. Attempting a window that overlaps an existing active reservation answers `409 HOTELING_DOUBLE_BOOKED`, with the conflicting reservation returned under `error.details.conflict` so you can show who booked first.

**List** (`GET /api/v1/voice/hoteling/reservations`) scopes the agenda to `?scope=me` (default) or `?scope=team`, with optional `from`/`to` and `deviceSipUsername` filters. The dashboard toggle **Mine / Team** maps directly onto `scope`.

**Cancel** (`DELETE /api/v1/voice/hoteling/reservations/:id`) — the booker cancels their own reservation; owner/admin can cancel any.

**Release** — two automatic paths keep desks from dead-locking:

* **No-show:** if the booker hasn't signed in **15 minutes** after their window starts, the reservation releases and the desk becomes walk-up again. Until that grace runs out, a different agent signing in to the reserved desk is rejected.
* **Elapsed sweep:** windows that have fully elapsed flip to `expired` on every read/book. Owner/admin can force it now with `POST /api/v1/voice/hoteling/reservations/sweep`.

## 4. Conflict prevention and clear priority

Conflict resolves deterministically at **booking time** — not at sign-in time:

| Situation                                                                                  | Outcome                                                                                  |
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| Window overlaps an existing `reserved`/`fulfilled` reservation                             | `409 HOTELING_DOUBLE_BOOKED`; the `error.details.conflict` names the holding reservation |
| Walk-up sign-in hits a desk reserved by someone else, still in the 15-minute no-show grace | Sign-in blocked; desk held for the booker                                                |
| Walk-up sign-in hits a desk whose booker exceeded the grace                                | Allowed; the reservation flips to no-show                                                |
| Two sign-ins race for the same device or user                                              | One wins; the other gets `409` and retries                                               |
| Signed-out phone receives inbound                                                          | Shared-pool inbound rule — never the prior occupant's extension                          |

The dashboard's **Team** scope is the disagreement-settler: if a booking "isn't mine," that view answers who holds it.

## 5. Security boundary

Sign-in **identifies** who is at the device; it does not create the agent's authentication. The session ledger records who, where (device SIP username), and when, and every transition lands in the [audit log](/guides/audit-log) with actor, device, and timestamps.

* **Role-gated access.** The page is visible to members with the `agent` role or above; revoke requires `owner`/`admin`. Customers decide who may sign in or look by assigning roles — this is entirely tenant-managed.
* **Calls remain authenticated.** The call itself rides the SIP credential the phone registered with (the shared-pool credential), so sign-in never carries the agent's own SIP secret to the device, and the post-release device has no residual access to the user's identity.
* **Grace is a release, not a bypass.** The 15-minute no-show grace only unlocks a *walk-up*; it never skips authentication.
* **Emergency calling is unchanged.** Orbit routes no emergency calls, hot-desking or not, so follow [Emergency calling](/voice/emergency-calling) regardless of who is signed in.

## 6. Worked example: staffing a rotating-shift call center

A support floor runs three daily shifts (07:00–15:30, 15:00–23:30, 23:00–07:30) on **40 shared phones** with **54 agents** on the roster. No agent owns a desk; the pool absorbs shift swap without hardware changes.

**Sample calendar walk-through** (one desk, `acme-shared-5F-2`, booked by the team planner via the API — the same thing the dashboard form does):

```bash cURL theme={null}
# Morning shift — agent A
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/hoteling/reservations" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"deviceSipUsername":"acme-shared-5F-2","startsAt":"2027-01-12T06:30:00Z","endsAt":"2027-01-12T15:30:00Z","notes":"Early shift A"}'

# Evening shift — agent B (window overlaps-safe: ends right as the next starts)
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/hoteling/reservations" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"deviceSipUsername":"acme-shared-5F-2","startsAt":"2027-01-12T15:00:00Z","endsAt":"2027-01-12T23:30:00Z","notes":"Late shift B"}'
```

Agent A signs in at 07:12 → session active, reservation flips to `fulfilled`. At 15:04 agent A forgets to sign out; agent B's 15:00 reservation lives in the system, so B's sign-in displaces A — release reason `displaced_by_new_session` in the ledger. One phone, three owners per day, zero re-provisioning.

If your shift rota feeds from an external scheduler, generate daily bookings with a loop over the agent/date pairs — the `409` on overlap acts as your safety net against a mis-scripted roster import.

## Tips

| Tip                                                                | Why                                                                                                             |
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| Label physical phones with their SIP username (`Floor 5 — Desk 2`) | Agents type the right value at sign-in instead of guessing the provisioning identifier                          |
| Set an end-of-shift expiry on every sign-in                        | Stuck sessions self-clear; the admin revoke page stays empty                                                    |
| Book the reservation before the shift starts                       | No-show grace holds the desk 15 minutes; booking after the start leaves a walk-up window someone else can claim |
| Use `Team` scope when a desk is "taken"                            | Shows who holds the reservation or session before you revoke                                                    |
| Revoke only for exceptions                                         | Expiry and displacement keep the ledger clean; revocation is for lost devices and departures                    |
| Keep the shared-pool inbound rule sane                             | Signed-out phones route somewhere sensible — a hunt group or the pool voicemail — rather than failing           |

## Troubleshooting

**Stuck session** — an agent left without signing out: open **Voice → Hot-desking**, find the row, and revoke. With an expiry set this clears itself.

**"A concurrent sign-in beat this one"** — two people signed in at the same moment; retry. Whoever signs in last holds the device.

**Sign-in blocked by a reservation** — the desk is held for a booker still inside the no-show grace. Either wait out the 15 minutes, pick another desk, or ask an admin to cancel the reservation if the booker is a genuine no-show.

**Double-booking** (`409 HOTELING_DOUBLE_BOOKED`) — the response names the conflicting reservation under `error.details.conflict`; show that to the booker instead of guessing. If a script imports a roster, fix the overlapping rows upstream.

***

## Related references

* [Hot-desking concept page](/voice/hot-desking) — device provisioning and the sign-in state machine detail
* [Voice hot-desking API reference](/api-reference/voice) — full field-level reference for the endpoints used above
* [Audit log](/guides/audit-log) — where every session and reservation transition is recorded
* [Emergency calling](/voice/emergency-calling)
* [Holiday and closure calendars for inbound voice](/guides/voice-calendars) — the related calendar for routing, separate from desk reservations
