> ## 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.

# Troubleshooting: voice call park orbit

> Resolve PARK_SLOTS_FULL, PARK_SLOT_OCCUPIED, PARK_ALREADY_RETRIEVED, and the sibling park-orbit rejects — map each code to the slot state that fired it and the fix you own.

# 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.

| Error code               | HTTP | Fired on                                                        | Go to                                          |
| ------------------------ | ---- | --------------------------------------------------------------- | ---------------------------------------------- |
| `PARK_SLOTS_FULL`        | 409  | Park, auto-pick: no slot between 1 and 9 was free               | [All slots occupied](#park-slots-full)         |
| `PARK_SLOT_OCCUPIED`     | 409  | Park into an explicit slot: that slot already holds a live call | [Requested slot occupied](#park-slot-occupied) |
| `PARK_SLOT_EMPTY`        | 404  | Retrieve: no live call currently sits in the slot               | [Retrieve an empty slot](#retrieve-codes)      |
| `PARK_ALREADY_RETRIEVED` | 410  | Retrieve: the slot's most recent call was already picked up     | [Retrieve codes](#retrieve-codes)              |
| `PARK_ALREADY_RELEASED`  | 410  | Release by park ID: that parked call was already released       | [Release reject](#release-reject)              |
| `PARK_NOT_FOUND`         | 404  | Release by park ID: no parked call exists under that identifier | [Release reject](#release-reject)              |

## All slots occupied — PARK\_SLOTS\_FULL<a id="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:

1. **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, and `parkedForSeconds` — a very large value marks the entries
   nobody picked up.
2. **Retrieve a stale entry.** A teammate retrieves the slot
   (`POST /api/v1/voice/park/retrieve` with `{ "slot": N }`, or dials
   `*N` from a registered device). Once a slot frees, retry the park.
3. **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.
4. **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/park` with
   `{ "callSid": "...", "slot": N }`).

The model is per-organization and staffed by the whole team's
org-wide roster: every member's parked call draws from the same nine
slots, so the fix is always "free a slot," not "clear your own."

## Requested slot occupied — PARK\_SLOT\_OCCUPIED<a id="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:

1. Read `details.occupant` — the occupant answers "who is on this slot?"
2. Re-issue the park with `slot` omitted 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<a id="retrieve-codes" />

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.prior` carries 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 `*N` at the same moment you tapped.

Fix both at the side that answered first — the 410 tells you the call
has an owning agent, and the `details.prior.retrievedByUserId` names
them.

## Release rejects — PARK\_ALREADY\_RELEASED / PARK\_NOT\_FOUND<a id="release-reject" />

`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 a
  `retrievedAt` stamp (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 one `park_…` 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 returned `PARK_ALREADY_RETRIEVED` for a slot
still showing in the live list — open a ticket with:

1. **The full error body** — code, message, and the `details` object
   (occupant or prior-retrieval view when present).
2. **The slot number and the park or retrieve identifier** involved.
3. **The park-id of any stuck entries** and the `parkedForSeconds`
   the live list shows for them.
4. **Your organization ID** (Settings → Organization, or
   `organizationId` from `GET /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`..`*9` is the fixed affordance,
  and slot `0` is not part of the orbit.

## See also

* [References: error codes](/reference/error-codes) — the error catalog
  this page triages against.
* [Troubleshooting: voice call quality](/troubleshooting/voice-call-quality) —
  once the park is clean and the complaint moves to audio.
* [Troubleshooting: SIP trunk](/troubleshooting/sip-trunk) — the
  registered-endpoint callers dial `*N` from when softphone retrieval is
  not the path.
