1. When to use SLA
Use a shared line when a team answers one identity together and anyone on the team may take over a live call:- Reception desk — the company’s main number rings on every device at the front desk; whoever is free answers.
- Executive assistant — the exec’s line appears on the assistant’s phone; the assistant screens, answers, and can hand the call to the exec without a transfer sequence.
- Coverage pairs — two agents covering the same window see the other’s line go busy and grab it when one steps away.
2. Create a shared line
Create the line first, then add members.POST /api/v1/voice/shared-lines requires a role with write access (owner, admin, or developer).
cURL
The 201 response returns the created line with an empty
members array — note the id, it goes in every later call. GET /api/v1/voice/shared-lines lists lines with cursor pagination (cursor, limit 1–100, default 50) and a per-line memberCount; GET /:id returns one line with its full roster.
3. Manage the member roster
Members are the devices the line rings.POST /:id/members and DELETE /:id/members/:memberId are write paths (owner/admin/developer).
cURL
Shape rules enforced at write time:
- A
sip_extensionmember must reference a live SIP credential for your organization — an unknown username answers422naming the value.user_idmembers are not existence-checked upfront; the fork layer resolves them at call time. - Each member value can appear once per line — a double-add answers
409(otherwise the fork would invite the same phone twice). - The roster is capped at 50 members — the 51st answers
409. - Removing the last member is allowed; the line simply rings nothing until you re-add one (the DID’s fallback route then covers it — see section 6).
cURL
204. Deleting the whole line (DELETE /api/v1/voice/shared-lines/:id) removes its roster too — there is no soft delete.
4. Poll live status
GET /:id/status is a read-only, side-effect-free endpoint the Shared Lines dashboard page polls to draw the busy lamp and decide whether to offer Grab. Front-desk roles can read it (owner, admin, developer, agent).
cURL
200 — line idle
200 — line busy
activeCall semantics — the busy lamp is accurate on purpose:
activeCall: nullmeans the line is idle. Only a call that actually arrived on the line (dialed to itsprimaryExtension, or arrives via a DID routed to this line) marks it busy. A member’s private or outbound call on their own phone never lights the line up.onDeviceUsernameis the SIP username of the member device currently holding the call. It isnullwhen the line demonstrably has a call but the answering device hasn’t been correlated yet (mid-bridge) — the field is never a guess.- Poll on a short interval (the dashboard does); the endpoint is safe to hit repeatedly.
5. Grab an in-use call
Grab moves the line’s currently answered call from whichever device answered onto your own device — the receptionist-assistant handoff without a transfer menu.POST /:id/grab is a live-call action open to agent role as well as operators.
cURL
grabbingMemberValue must be a sip_extension member of this line’s roster with canGrab true — the receiving device, not the device that answered.
The full walkthrough:
- Line is active (409 otherwise). An
inactiveline cannot be grabbed. - You must be on the roster with grab permission (403). A
grabbingMemberValuethat isn’t asip_extensionmember of this line, or hascanGrab: false, is rejected with403— the membership flag is the gate, not just the roster. - The line must have an answered call (404 otherwise). Grabbing while
activeCallis null answers404. Only a call on the line itself can be grabbed; a member’s private call is invisible to this endpoint, so a private call can never be pulled onto a colleague’s phone. - You can’t grab the device already holding it (409). If
onDeviceUsernamewas resolved and equals yourgrabbingMemberValue, the request is a no-op409. - Only one grabber wins (dedup). Claims race on a short atomic window, so two members hitting Grab in the same instant get one
200and one409. A retry of the same request id is equally safe — it reports conflict instead of double-moving the call.
200
6. Point a DID at the line
A shared line has no inbound traffic until a DID routes to it. On the number’s routing config, settype: "shared_line" with config.sharedLineId — the same picker under Numbers → number → Routing and the same API as every other route type (full guide: Pick the right inbound routing for a DID).
cURL
config.ringTimeoutSec is optional (5–120). Set a fallback so a call answers somewhere when the roster is empty or nobody picks up — route-specific notes on fallbacks are in the routing guide. Internal dials straight to the line’s primaryExtension also reach the line without touching a DID.
7. Errors and dedup semantics
The grab claim is atomic (a short-window dedup slot, same primitive used across the live-call endpoints), so safe-retry and racing-members semantics hold: one winner, conflict for the rest, and no double-move.
See also: Pick the right inbound routing for a DID · Extensions vs. Colleagues · Paging, ring groups, and call park