Skip to main content

Troubleshooting: hoteling reservation cancel and revoke rejections

The reservation calendar books a specific desk phone for a future window; walk-up hot-desking binds an agent to a phone right now. The two surfaces share one desk pool but carry separate reject vocabularies: reservation-lifecycle rejections are HOTELING_* codes and are this page; sign-in / sign-out / revoke rejections are HOT_DESK_* codes and live in Hot-desking sign-in rejects. The booking-time collision HOTELING_DOUBLE_BOOKED is covered in the hot-desking guide. Every reject below is a reservation-state or role guard your organization owns — your roles, your calendar, your cancels. None of them touches a live call or the desk phone’s SIP registration.

Code matrix — which state or role fired

Find the error code first, then jump to its section below.

No reservation under that id — HOTELING_NOT_FOUND

404 HOTELING_NOT_FOUND fires on DELETE /api/v1/voice/hoteling/reservations/:id when the id matches no reservation in your organization — the id never existed here, or the request is hitting a different workspace than the one it was booked under. A look-up trap separate from the reject: the agenda defaults to ?scope=me, so a teammate’s id must be found through Team scope before you can re-target a cancel at it. Fix it by re-listing before you re-target:
  1. List with team scope. GET /api/v1/voice/hoteling/reservations?scope=team shows every reservation in the organization, including the ones your me list hides.
  2. Re-target a live id. Cancel against the id exactly as that list returns it.
  3. If the team scope still 404s, the id was never created under this organization — check that the request and the API key belong to the same workspace.

Role check — HOTELING_FORBIDDEN

403 HOTELING_FORBIDDEN fires when someone other than the booker attempts a cancel. The rule is one line: the booker cancels their own reservation, an owner or admin cancels any, and everyone else 403s. Fix it by routing the cancel to the right actor:
  1. If the reservation is yours, retry with the booker’s own credential — a different member’s key or session 403s no matter what it intends.
  2. If it is someone else’s, ask them to cancel it from their Mine agenda view, or have an owner/admin run the same DELETE, which succeeds for them.
  3. Check the holder before retrying: the Team scope on Voice → Hot-desking names the booker of any row.
If this reject is frequent, your roster is routing cancels through accounts that are neither bookers nor admins — adjust member roles in your organization settings, which is entirely tenant-owned.

Terminal reservations — HOTELING_NOT_CANCELLABLE

410 HOTELING_NOT_CANCELLABLE fires when the reservation already ended. A reservation ends in exactly four ways:
  • fulfilled — the booker signed in during the window; the desk went to their session.
  • cancelled — an earlier cancel won; this call is the second tap.
  • expired — the window fully elapsed; the elapsed sweep flips these, and owner/admin can force it now with the sweep endpoint.
  • released as a no-show — the booker never signed in and the 15-minute grace ran out.
In all four there is nothing left to cancel: the desk is either held by a session or back in the walk-up pool, and the 410 message names the final state. The same 410 also settles a race where a cancel lands at the same instant as another cancel or a sweep / no-show release — exactly one of them wins. Fix it by acting on the desk, not the old row:
  1. Treat the row as closed. Re-read it with the team-scope list if you need the final state for your records.
  2. Book another window. A fresh POST /api/v1/voice/hoteling/reservations is how the desk gets claimed again; a terminal reservation no longer holds it.
  3. Owner/admin reconciling the calendar: POST /api/v1/voice/hoteling/reservations/sweep flips elapsed reserved rows to expired now and reports the released count — use it when the agenda shows windows that already passed.

What to capture before escalating

Work the matrix above first. If a code keeps firing after a clean team-scope re-list — a 404 on an id the live team list shows, or a 410 on a row the list still shows as reserved — open a ticket with:
  1. The full error body — code, message, and any details object.
  2. The reservation id and the device SIP username involved.
  3. The row as the team agenda shows it when the live list and the reject disagree.
  4. Your organization ID (Settings → Organization, or organizationId from GET /api/v1/me).

What not to do

  • Do not retry-loop a 410. Terminal is terminal; the desk decision is final, and looped cancels cannot reopen a fulfilled or expired window.
  • Do not treat a 403 as a broken credential. The credential works; it simply is neither the booker’s nor an owner/admin’s.
  • Do not cancel from a stale list. Re-list with ?scope=team before any scripted cancel batch; most 404s are ids copied from an agenda fetched before a release ran.

See also