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

# Answer anyone's ringing call and move live calls between phones

> Directed pickup, group pickup, and call flip — answer a colleague's ringing extension from yours, and move a live call from your desk phone to your mobile (and back) without interrupting the caller.

# Answer anyone's ringing call and move live calls between phones

Two inbound-portability workflows cover the "the call is ringing/somewhere
else" problems a softphone-only setup can't solve:

* **Call pickup** — answer a call that is *ringing* on a colleague's
  extension, from your own device. **Directed pickup** lets you name the
  extension ("answer whatever is ringing on 201"); **group pickup** takes
  the longest-ringing call in your pickup group without naming a
  target.
* **Call flip** — move a call you already *answered* from one of your
  registered devices to another (desk phone → mobile, or back), while
  the caller stays on the line.

Both work on any SIP device registered to your Orbit account — desk
phones (Yealink, Grandstream, Polycom) and softphones (the Orbit
dashboard softphone, mobile app, Linphone, Bria, Zoiper) behave
identically.

<Note>
  Pickup and flip only ever re-target a live leg to another device on
  your own tenant. Neither feature originates a new external call — the
  actual phone call still exits through the same wholesale route it
  arrived on.
</Note>

## Pick a workflow

| Situation                                                             | Use                                                                         |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| "Sarah is away from her desk — grab her ringing call from mine"       | Directed pickup (`POST /voice/pickup/directed`)                             |
| "Someone in the support hunt group is ringing — take the oldest call" | Group pickup (`POST /voice/pickup/group`, or `*8` on a desk phone)          |
| "Show me everything currently ringing that I could pick up"           | Pickup tray (`GET /voice/pickup`)                                           |
| "I answered on my desk phone but I'm leaving — continue on my mobile" | Call flip (`POST /voice/call-flip` → `POST /voice/call-flip/pull`, or `*7`) |
| "Move a call to a specific colleague, not just one of my own devices" | Use [attended transfer](/voice/attendant-console) instead                   |
| "Stash my own active call for later retrieval from any phone"         | Use [call park](/voice/paging-ring-groups-call-park) instead                |

***

## Ringing-legs index (how pickup knows what's ringing)

Pickup needs a live view of which inbound calls are ringing and on
which extension. Orbit keeps this in a sub-30-second **ringing-legs
index**:

* When an inbound call starts ringing on an extension, the voice
  webhook registers it; when the caller hangs up or someone answers,
  the webhook clears it. These register/clear hooks are internal
  system-to-system calls, authenticated with the internal service
  token — you don't call or configure them directly.
* The `GET /api/v1/voice/pickup` **pickup tray** lists the current
  ringing calls oldest-first, so dashboards and softphone UIs can
  render a "calls you can pick up" panel.

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/voice/pickup \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Each entry reports the target extension, the caller's number and name,
and how long it has been ringing:

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "callSid": "9186a01a-0f9b-4c4e-9dd2-1c9b82f3c1e7",
      "targetExtension": "201",
      "targetUsername": "sarah.desk",
      "callerNumber": "+442071234567",
      "callerName": "A. Customer",
      "ringingSince": "2026-08-28T09:14:02.110Z"
    }
  ]
}
```

An outdated tray entry simply loses the races below — pickup claims
are atomic, so a stale row can never cause a double answer.

***

## Directed pickup — answer a specific extension's ringing call

Directed pickup is the dashboard/API equivalent of dialling
`**201` ("answer whatever is ringing on extension 201") on a
traditional PBX:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/pickup/directed \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "targetExtension": "201",
    "pickingUpDeviceUsername": "jordan.softphone"
  }'
```

* `targetExtension` — the extension (or SIP username) the ringing call
  is aiming at.
* `pickingUpDeviceUsername` — **your** device's SIP username (from your
  list of SIP credentials). The call is bridged to that device.

On success you get the resolved call plus the bridge instruction:

```json theme={null}
{
  "ok": true,
  "data": {
    "callSid": "9186a01a-0f9b-4c4e-9dd2-1c9b82f3c1e7",
    "targetExtension": "201",
    "callerNumber": "+442071234567",
    "callerName": "A. Customer",
    "ringingSince": "2026-08-28T09:14:02.110Z",
    "bridgeToDeviceUsername": "jordan.softphone",
    "pickupType": "directed"
  }
}
```

If nothing is ringing on the named extension, the request returns
`404` ("no call ringing on that extension"). If two colleagues go for
the same call at the same moment, exactly one wins — the loser gets a
`409` and the call is never bridged twice.

## Group pickup — grab the oldest ringing call in your group

Group pickup is the equivalent of dialling `*8` — "answer the
longest-ringing call in my pickup group," no target needed:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/pickup/group \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "pickingUpDeviceUsername": "jordan.softphone" }'
```

* With no `groupMembers`, your pickup group is the whole tenant — the
  classic `*8` "grab any ringing call" behaviour.
* Pass `groupMembers` (an array of extension/SIP usernames) to restrict
  the pool to a named team's ringing calls:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/pickup/group \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pickingUpDeviceUsername": "jordan.softphone",
    "groupMembers": ["sarah.desk", "priya.desk"]
  }'
```

The response shape matches directed pickup, with `pickupType: "group"`.

<Note>
  Every successful pickup writes an audit-log entry with the picking
  user, the resolved call, and the target extension — so "who took that
  call?" is answerable after the fact.
</Note>

***

## Call flip — move a live call between your own devices

Call flip handles the commute/meeting problem: you're on a live PSTN
call on your desk phone, and you want to keep talking from your mobile
(works in the other direction too).

### 1. Push — issue a handoff from the current device

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/call-flip \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "callSid": "9186a01a-0f9b-4c4e-9dd2-1c9b82f3c1e7",
    "targetDeviceUsername": "jordan.mobile",
    "remotePartyNumber": "+442071234567",
    "remotePartyName": "A. Customer"
  }'
```

* `callSid` — the live call you're flipping. The dashboard's
  active-call view carries it; it's also in the pickup response when
  you took the call.
* `targetDeviceUsername` (optional) — pin the handoff to one device so
  only that SIP username can pull it, or omit it so *any* of your
  registered devices can pull.
* The remote-party fields (optional) make the dashboard's pending-flips
  list easier to scan.

The response hands back a `token` (full secret), a 4-digit `shortCode`
for desk-phone dialling, and an `expiresAt`; unused handoffs
expire after two minutes:

```json theme={null}
{
  "ok": true,
  "data": {
    "token": "cf_9d3f…redacted",
    "shortCode": "4239",
    "expiresAt": "2026-08-28T09:16:02.110Z"
  }
}
```

Re-pushing a flip for a call you already flipped returns the existing
handoff instead of stacking duplicates.

### 2. Pull — claim the handoff from the other device

From the second device (pressing "Pull call" in the dashboard or mobile
app):

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/call-flip/pull \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "token": "cf_9d3f…",
    "pulledByDeviceUsername": "jordan.mobile"
  }'
```

* `token` — the full token from the push, or the 4-digit short code on
  the dial path.
* `pulledByDeviceUsername` — the SIP username of the device doing the
  pull; if the push pinned a target device, it must match.

The pull resolves the live call so your client can signal the bridge
and release the first device.

### Legacy desk phones — `*7` plus the short code

Phones with no dashboard access dial `*7` then the 4-digit
`shortCode` (for example, `*7 4239#`); the voice platform claims the
handoff on that phone's registered identity. The claim is validated
with the same expiry/competition rules as the API pull.

### Expiry and racing

Pulling an expired handoff returns `410` with `expiredAt`; pulling one
another device already claimed returns `410` with which device won, so
you can tell which phone took the call. A handoff belongs to your
tenant — the token alone grants nothing to anyone outside it.

### Track and cancel

`GET /api/v1/voice/call-flip` lists your pending flips (for the
dashboard's pending list), and a push can be withdrawn before a pull
with:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/voice/call-flip/<handoff-id>/cancel \
  -H "Authorization: Bearer YOUR_API_KEY"
```

***

## Prerequisites and scope

* **Devices**: the picking-up or pulling device must be a registered
  SIP device under your tenant (Voice → SIP credentials in the
  dashboard). Any standards-compliant SIP endpoint works — desk phone
  or softphone.
* **Roles**: pickup and flip endpoints require one of the workspace
  owner, admin, developer, or agent roles. The internal ringing-index
  and dial-code hooks are platform internals and not part of the
  customer API.
* **Inbound only**: pickup re-targets a *pre-answer inbound* leg; it
  never originates a new external call and never hands a call to an
  outside number. Call flip likewise moves the call only between your
  own registered devices. For anything else — an external party, a
  colleague on an outside line — use transfer instead.

## Related

* [Attendant console](/voice/attendant-console) — run pickups and
  transfers from a receptionist's desk.
* [Paging, ring groups & call park](/voice/paging-ring-groups-call-park) —
  group distribution and stashing your own active call.
* [Browser softphone](/guides/voice-softphone-browser-calling) — the
  device registration and credential setup every registered device
  depends on.
