Troubleshooting: voice call park orbit
Call park works like a bank of numbered parking spots: your organization gets nine shared slots, numbers 1 through 9, and every parked call occupies one until someone retrieves it. A softphone taps “Park” and the call lands in a slot with on-hold music; any agent in the organization retrieves it by picking that slot’s number in the softphone or dialing*N on a registered device.
This page maps each park-orbit error code to the slot state that
produced it and the fix you own. All rejects below are pre-bridge
guards — the caller still hears hold music and no party is dropped.
Code matrix — which slot state fired
Find the error code first, then jump to its section below.All slots occupied — PARK_SLOTS_FULL
409 PARK_SLOTS_FULL fires when a park attempt leaves slot selection
unspecified — the normal “Park” button path — and the auto-pick finds
no free slot between 1 and 9. The error body carries
details.occupiedSlots, the sorted list of slot numbers holding live
calls, so you can see which slots are stuck.
Fix it by freeing a slot, releasing by hand, or parking explicitly:
- List the live parked calls (
GET /api/v1/voice/park, or the parked-calls panel in the softphone). Each entry shows the slot, the caller, andparkedForSeconds— a very large value marks the entries nobody picked up. - Retrieve a stale entry. A teammate retrieves the slot
(
POST /api/v1/voice/park/retrievewith{ "slot": N }, or dials*Nfrom a registered device). Once a slot frees, retry the park. - Or release by park ID. An operator clears a stale entry with
POST /api/v1/voice/park/{parkId}/release— the timed-out-for-days case where the eventual retrieve never happened. - Or park into a named slot. If a slot in the range 1 to 9 is free
and the reject fired anyway, the client picked an occupied slot from
a stale pre-park list — re-list and name a slot the fresh list does
not show (
POST /api/v1/voice/parkwith{ "callSid": "...", "slot": N }).
Requested slot occupied — PARK_SLOT_OCCUPIED
409 PARK_SLOT_OCCUPIED fires when the park body named an explicit
slot and that slot already holds a live call. The response carries
details.occupant — the slot’s current occupant view with caller
number, parked-at time, and elapsed seconds — so the client can render
“Slot 4 busy since 0:42 (Alice, +14155…)” instead of a bare 409.
Two park races into the same slot within a few milliseconds resolve
through this same code — the second attempt is the lost race against the
live-slot uniqueness guard, so retrying it never makes it through.
Fix it by parking into a different slot:
- Read
details.occupant— the occupant answers “who is on this slot?” - Re-issue the park with
slotomitted and let auto-pick take the lowest free one, or name a slot the occupant view does not hold.
Retrieve rejects — PARK_SLOT_EMPTY / PARK_ALREADY_RETRIEVED
Retrieve path (POST /api/v1/voice/park/retrieve or the dial *N) is
idempotent against slot state — calling it when nothing live sits in
the slot returns one of two codes:
404 PARK_SLOT_EMPTY— no live call is currently parked in the slot. The slot was never parked, or it freed earlier and nobody picked anything back into it. Re-list (GET /api/v1/voice/park) and retrieve the slot the list shows as live.410 PARK_ALREADY_RETRIEVED— the slot’s most recent parked call was already claimed.details.priorcarries the retrieval metadata (retrieved-by user ID, retrieved-at time, elapsed parked seconds), so the client can answer “Who took it?” — usually the teammate across the floor who dialed*Nat the same moment you tapped.
details.prior.retrievedByUserId names
them.
Release rejects — PARK_ALREADY_RELEASED / PARK_NOT_FOUND
POST /api/v1/voice/park/{parkId}/release clears a specific parked-call
record by its park_… identifier:
410 PARK_ALREADY_RELEASED— the record exists but already carries aretrievedAtstamp (it was retrieved or previously released). Safe to treat as success — the slot is free.404 PARK_NOT_FOUND— no parked call exists under that identifier, usually because the ID came from an earlier list response that another release has since aged off the live view. Re-list before re-issuing the release.
Server-side maps — what the records look like
A parked call is onepark_… record with the slot, the parking user’s
ID, the caller’s E.164 number and display name, a parkedAt timestamp,
and a server-computed parkedForSeconds the dashboard renders as the
elapsed badge. The record flips retrievedAt exactly once — retrieve,
release, the park-timeout sweeper, or the caller hanging up — so the
live view is at most nine rows, sorted newest first.
Auto-pick parks scan slot 1 through 9 and land in the first free one;
a fixed-slot park goes straight to the requested slot. Either way, a
concurrent pair of parks of the same slot resolves to the occupant-code
409 above, never to a double-parked slot.
A 409 or 410 in this class is not a server misread — it reports a
true slot-state conflict, so if the dial keeps firing them after every
fix above, work the checklist below before escalating.
Do you legitimately need more slots?
The orbit is bounded to nine slots on purpose — that’s the retro-telephone affordance*1..*9 mapped onto single-digit DTMF
retrieval codes, and adding a 10th slot breaks both the dial codes and
the muscle memory the feature takes its name from. The orbit model
trades slot-capacity for familiarity.
The nine-slot cap clears itself when retrieval or release happens
promptly. When your org consistently parks more than nine live calls
at once, the fix is coordination, not a call for a capacity flag —
this is a shared bank, and every new claim on it steals one from
someone else’s retrieval list. Where the need is real, these alternatives pick up the load:
- Use the queue path for inbound volume — inbound callers waiting for an agent belong in a queue, which holds hundreds; park slots are the shared operator lobby, not the customer inbound queue.
- Ring a named teammate — target a specific user or device with a transfer instead of the shared-lobby model.
- Flag a sustained saturation pattern to support — if your org genuinely fills all nine slots day after day, that says the traffic moved past the lobby pattern; scope the right model with support rather than retraining the team on new dial codes.
What to capture before escalating
Do the fixes above first. If the code still fires — the slot genuinely was free, or a retrieve returnedPARK_ALREADY_RETRIEVED for a slot
still showing in the live list — open a ticket with:
- The full error body — code, message, and the
detailsobject (occupant or prior-retrieval view when present). - The slot number and the park or retrieve identifier involved.
- The park-id of any stuck entries and the
parkedForSecondsthe live list shows for them. - Your organization ID (Settings → Organization, or
organizationIdfromGET /api/v1/me).
What not to do
- Do not retry the same explicit-slot park in a loop. The occupant-code 409 resolves to whom you should call — do that instead.
- Do not treat 409/410 as a crash. They are pre-bridge slot guards; the caller stays on hold music through every one of them.
- Do not re-map the dial codes.
*1..*9is the fixed affordance, and slot0is not part of the orbit.
See also
- References: error codes — the error catalog this page triages against.
- Troubleshooting: voice call quality — once the park is clean and the complaint moves to audio.
- Troubleshooting: SIP trunk — the
registered-endpoint callers dial
*Nfrom when softphone retrieval is not the path.