Skip to main content

Work the Parked Calls lobby

Call park is the classic operator hand-off: put a live caller into a numbered slot, tell a teammate which slot to pick up, and they retrieve the call from their own phone. The Parked Calls page under Voice is the shared lobby where every operator sees the live parked calls, with a retrieve and a release action on each row. Park is one of four control-plane endpoints over the tenant’s voice API. Use it when a call must move between people or devices without a conference bridge — the caller hears hold music, the first retrieval at any phone wins, and the slot frees for the next hand-off.

1. Park slots and the four endpoints

Your organization gets nine shared slots, numbered 1 through 9. A park puts one live call on one slot; the caller hears hold music until someone retrieves the slot or the call hangs up. Retrieve and release are one-stroke claims — the first succeeds and every later attempt returns a clear error instead of a race. Two operators parking into the same slot within milliseconds resolve through a single occupancy check — the first succeeds, the second receives a 409 PARK_SLOT_OCCUPIED with the occupant’s slot, caller, and elapsed time. The PARK_… error codes are mapped to fixes in Troubleshooting: voice call park orbit.

2. Worked responses for every endpoint

Every call below is tenant-scoped under /api/v1/voice/park — the Voice API reference covers the shared base path and auth headers; the body-level diagnosis for each PARK_… code lives in the voice call park troubleshooting catalog.

List live parked calls — GET /api/v1/voice/park

cURL
200
The list returns the tenant’s live slots newest-first with the server-computed parkedForSeconds badge, so a lobby client never re-computes elapsed time client-side.

Park a live call — POST /api/v1/voice/park

cURL
Omit slot and the park auto-picks the lowest free slot (the same digits a desk phone dials with *N). Send "slot": 4 when the operator named a number deliberately.
201
201 carries the picked slot so the client goes straight to the “Parked on slot 3” toast. If all nine slots are occupied, the park returns 409 PARK_SLOTS_FULL with the occupied-slot list:
409

Retrieve a parked call — POST /api/v1/voice/park/retrieve

cURL
200
Retrieve claims the slot atomically — the row’s retrievedAt and releaseReason flip in one write and the slot frees for the next park. A retrieve against a slot nobody ever parked is a 404 PARK_SLOT_EMPTY.

Release a parked call — POST /api/v1/voice/park/:id/release

Release frees the slot without bridging the caller back. The :id is the park_… id from the list row, not the slot number.
cURL
200
The success body carries the released row, never an empty envelope.

3. Collision envelopes — 409, 410, and 403

Park’s concurrency primitives push the race decision to the client: every live claim is one-stroke, and the losing attempt gets a body that names the winner. These shapes drive the retry / different-slot logic in a client, so they are shown in full.

409 PARK_SLOT_OCCUPIED — park into a taken slot

A named slot in the park body that collides returns 409 with the current occupant’s slot, caller, and elapsed hold time — enough to re-park on a different slot or point the operator at the winner.
409
Auto-pick (no slot in the body) never collides — it claims the lowest free slot in one transaction. This 409 only fires when the operator deliberately named a slot number.

410 PARK_ALREADY_RETRIEVED — retrieval race

Two operators retrieving at the same moment resolve to one claim: the winner gets 200 and the loser gets 410 with the winning claim’s full view (including retrievedByUserId) — safe to treat as taken instead of a failed call-flip.
410
The release endpoint has its own variant — re-releasing an :id flips 410 PARK_ALREADY_RELEASED with the same { "prior": {…} } contract, and an unknown id is 404 PARK_NOT_FOUND:
410
The voice call park troubleshooting catalog maps each of these codes to a fix for clients driving them.

403 INSUFFICIENT_PERMISSIONS — role guard

Every endpoint in this surface is gated server-side by the same role list the lobby page displays — owner, admin, developer, agent. A viewer or observer token is refused before any body validation:
403

4. Polling the lobby — SDK pattern

The dashboard polls /voice/park every ten seconds and renders each row. A light client does the same through the SDK’s generic orbit.request() helper — the only client-side surface on this page, so this is the one sample that matters.
Node.js
Poll every ten seconds, render the rows, and treat the collision envelopes above as loop-back signals: a 409 re-parks on a different slot (or gives up), a 410 drops the row from the local list.

5. Who can act on a parked call

Parked rows carry the caller’s number and display name — a PII-bearing surface. The lobby and every control-plane action are restricted to owner, admin, developer, and agent roles (the dashboard page mounts a role guard showing the role you need; the API routes enforce the same guard server-side). Viewer and observer roles see nothing on the lobby. If you only expect to supervise, take the read path: the GET list is a read guard, so a role with read-only permission on parked calls still cannot park, retrieve, or release.
Every park, retrieve, and release writes an audit event with the operator, the slot, and the caller’s E.164 number. The audit log is the record of who claimed a held caller.

6. Park from the active call, retrieve from the lobby

Parking starts on the active-call surface; the lobby is where the row lands.
  1. Answer the caller from the browser softphone or your registered device. The active-call surface shows a Park action.
  2. Click Park. The softphone sends POST /api/v1/voice/park with the call SID and auto-picks the lowest free slot — the toast naming the slot number (for example “Call parked — slot 3”) is the confirmation. To place a specific slot, the same call carries a slot field when you pick one explicitly.
  3. Open Voice → Parked Calls. The new row appears within one poll cycle (the list refreshes every ten seconds) with the slot number, the caller’s number and name, and a live “parked for” counter.
  4. Any teammate retrieves the caller by clicking Retrieve on the row — or by dialing *N for the slot number on any registered device. The first retrieval wins; the row drops off every operator’s lobby on the next poll.
Releasing a stray parked call. When a caller should never have been parked, or a row will not be picked up, click the release (circle-x) action and confirm. Release is destructive and cannot be undone — it frees the slot and drops the held caller.

7. Slot naming and collision conventions

Agree on the naming discipline with the team before parking:
  • Auto-pick is the default. Leave the slot field blank and park slots claim the lowest free number (the same digits a desk phone dials with *N). Team muscle memory stays consistent — the numbers mean “next free slot,” not “my slot.”
  • Named slots are for deliberate placement. When a receptionist says “Mr Santos is on 2,” the number is the message. Pick the slot explicitly and the occupant’s 409 response carries the info needed to re-park elsewhere.
  • Never let auto-pick hide a collision. A 409 on a named slot means another operator claimed it first — the response also carries on the occupant view the parked-at time and the caller info, so name the free slot and re-issue rather than retrying the same slot.

8. Hold and abandon discipline

The nine slots are a shared, finite lobby. Every row carries a running elapsed counter the whole floor sees, so a parked call that goes unanswered for minutes is visible to everyone — that is the abandon signal to act on before the caller hangs up. Decide the team’s longest-hold window (for example, two minutes). When a row crosses it, one of three things should happen:
  • Retrieve the row — the slot frees normally.
  • Release the row — when retrieval would mean an abandoned call is dropped anyway; confirm the destructive action.
  • Route inbound into a queue instead — if the same caller would have waited in a queue, the queue’s SLA and abandon metrics own the recording; park is the wrong surface for that flow.
A row that ages past the retention horizon clears server-side, so a forgotten park does not hold a slot forever — the running timer is for the team to act, not for the platform to babysit. (For a bounded pool model, see the troubleshooting page’s “Do you legitimately need more slots?” section; inbound volume belongs on queues.)

9. Worked example — the receptionist’s hand-off

Acme’s receptionist covers the main number from a browser softphone.
  1. A caller asking for Billing lands on the desk. The receptionist answers, speaks to the caller, and clicks Park — auto-pick claims slot 4.
  2. The toast reads “Call parked — slot 4”; the receptionist tells the billing specialist “Billing on 4.”
  3. The specialist opens Voice → Parked Calls, clicks Retrieve on the row for slot 4 (or dials *4 from a desk phone); the first attempt bridges the caller and frees the slot.
  4. While the specialist talks, the ticket the team keeps for this caller updates as the parked row’s parkedForSeconds shows the elapsed hold time — the lobby is the ground truth for “how long has this caller been on hold?”
If two operators had clicked Retrieve at the same moment, the second would see 410 PARK_ALREADY_RETRIEVED naming the retriever — safe to treat the claim as taken (see Troubleshooting).

10. When NOT to use park

Park is a per-slot, team-visible lobby — not a queue, and not a warm transfer.
  • Inbound volume belongs on a queue. A queue holds hundreds of callers in FIFO order with SLA metrics; park holds nine total live calls against the team. Route inbound numbers to a voice queue and park only for hand-offs the queue cannot dispatch.
  • A known teammate belongs on a transfer. Blind-transfer targets a named extension with a single click through the attendant console — park is for the “anyone can grab this caller” pattern, not a directed hand.
  • Warm hand-off belongs on a conference. When the specialist must hear who is on the line first, use a warm transfer or the conference bridge — never park, since there is no announcement step before the retrieve claim.

See also