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

# Ring groups end to end

> Create a named group of ring destinations, pick a strategy, attach it to a DID, test it, and tune it — plus the API endpoints and the queue-vs-ring-group decision.

A ring group is a saved list of destinations — SIP extensions, phone numbers, or other ring groups — that one inbound call fans out to. You build the group once, then point any number of DIDs at it. This guide walks the full operator loop: create the group, pick a strategy, attach it to a number, verify it, and tune the behavior.

**Base path:** `/api/v1/voice/ring-groups`

**Authentication:** Clerk session (`Authorization: Bearer <token>`) or API key (`X-API-Key`).

**Scope:** create, update, and delete require an owner or admin role. Reads are available to owner, admin, developer, and viewer roles.

***

## 1. When a ring group beats a queue

Both answer inbound calls with a group of people, but they behave differently at call time:

* **Ring group** — the inbound call rings member destinations directly (SIP devices, external numbers, or even other ring groups). The first member to answer owns the call. There is no hold position, no queue depth, and no agent staffing model.
* **Queue** — the caller waits in FIFO with hold music and a position, and the platform dispatches them to an eligible, available agent. Queues give you SLA metrics, occupancy, and agent-level routing; ring groups give you "ring these phones."

Pick a ring group when the destinations are *devices or numbers* (the pilot desk's deskphones, the on-call cell phone). Pick a queue when the destinations are *staffed agents* and you need hold, ordering, or service metrics. Every setting below is tenant-owned: your organization controls the group roster, the strategy, and where it attaches.

***

## 2. Create the group in the dashboard

Open **Voice → Ring groups** and click **Create ring group**. The modal carries three fields:

* **Name** — unique per organization (1–100 characters).
* **Strategy** — how the group offers the call to its members: `simultaneous` rings every member at once; `sequential` rings one member at a time in list order; `round_robin` rotates the starting member on each call; `longest_idle` offers the member who has been idle longest; `fewest_calls` offers the member with the fewest handled calls.
* **Ring timeout** — how long the group tries members before the DID's fallback or voicemail fires (5–300 seconds; default 30).

Members are rows in the members editor. Each row is one of:

* **SIP username** — an extension registered under **Voice → Extensions / Devices**.
* **Phone number (PSTN)** — an E.164 number with leading `+` (e.g. `+14155550123`). The leading `+` is required; a bare-digit number is rejected.
* **Ring group** — another group in your organization, for nesting (e.g. "front desk" inside "all support"). Cycles are rejected.

As you edit members, the dashboard runs a pre-save check and disables Save with an inline reason when the roster is empty, a cycle would close, or a member does not resolve. It also warns — but does not block — when a phone number already belongs to another group (useful to know before you overlap two groups on the same cell).

The group appears in the table as soon as you save; a group with zero members cannot be saved at all, so there is no half-created state.

***

## 3. Attach it to a DID

A ring group does nothing until a routing rule references it. The common pattern is a DID whose primary route is the group:

**Dashboard:** **Numbers → *your number* → Routing**, pick **Ring group** as the route type, and select the group.

**API:** `PUT /api/v1/numbers/:e164/routing` with `type: "ring_group"` and the sibling `ring_group_id` field — the config object is empty because the group identity lives in that sibling field.

```bash cURL theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/numbers/+14155550123/routing" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ring_group",
    "ring_group_id": "ringgroup_abc123",
    "fallback_type": "voicemail",
    "fallback_config": { "maxDurationSec": 120 }
  }'
```

Two attachment rules to avoid a silent misroute:

* **Send the group id as `ring_group_id`, not inside `config`.** `config` accepts `{}` for this type; a `config.ringGroupId` key is rejected as a shape error.
* **Pair it with a fallback.** If every member is busy or offline, the route falls through to the DID's fallback (`voicemail` in the example above). Without a fallback, the caller hears nothing useful.

Ring groups also sit one rung down in a queue's fallback ladder: if the queue has nobody available, the group rings; if the group also doesn't answer, voicemail catches the call. Use that pattern when you want two tries before a mailbox.

***

## 4. Test with the IVR simulator and call log

For the `ivr` route type, the simulator (`POST /api/v1/voice/ivr-flows/:id/simulate`) walks the published flow without burning a live minute — run it before attaching a flow that routes into a ring group. The response returns the nodes visited and the verbs emitted per turn, so you can confirm the flow reaches your group step before callers do.

For a directly-attached ring group, verification is a real inbound call to the DID, watched in the **Calls** log — you see each member destination rung and which one answered, plus whether the fallback fired. Attach-time validation rejects a bad group id with a `422`, so a misroute surfaces at write time rather than at ring time.

***

## 5. Tune the strategy

The strategy changes fan-out behavior more than anything else:

* **`simultaneous`** (default) — fastest answer; every member rings and the first to pick up owns the call. Right when the group is a handful of destinations and you want the shortest time-to-answer. The trade-off is that it can ring phones nobody wants to answer.
* **`sequential`** — rings one member at a time in roster order. Right when you have a defined order (lead first, then deputies). Slower to answer than simultaneous because each member's ring timeout runs in series.
* **`round_robin`** — rotates the starting member so share is even over many calls. Right when members are interchangeable and you want fairness rather than speed.
* **`longest_idle`** — offers the member idle longest. Right when you want to spread load without a round-robin rotation.
* **`fewest_calls`** — offers the member who has handled the fewest calls. Right when you want to even out handled-call counts over a shift.

Start with `simultaneous` for a small desk (the whole group rings, first answer wins) and revisit once the ring log shows one member answering most calls.

***

## 6. API walkthrough

Manage the roster from code the same way the dashboard does:

```bash cURL theme={null}
# Create — names the strategy and members in one shot
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/ring-groups" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "After-hours pilot desk",
    "strategy": "simultaneous",
    "ringTimeoutSec": 20,
    "members": [
      { "kind": "sip_username", "value": "desk-100" },
      { "kind": "sip_username", "value": "desk-101" },
      { "kind": "pstn", "value": "+14155550123" }
    ]
  }'

# List groups (alphabetical)
curl "https://api.orbit.devotel.io/api/v1/voice/ring-groups" \
  -H "X-API-Key: dv_live_sk_your_key_here"

# Read one
curl "https://api.orbit.devotel.io/api/v1/voice/ring-groups/ringgroup_abc123" \
  -H "X-API-Key: dv_live_sk_your_key_here"

# Partially update — members, when sent, replace the whole roster
curl -X PATCH "https://api.orbit.devotel.io/api/v1/voice/ring-groups/ringgroup_abc123" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "strategy": "round_robin" }'

# Delete (hard delete; inbound routes pointing at it fall back to org default)
curl -X DELETE "https://api.orbit.devotel.io/api/v1/voice/ring-groups/ringgroup_abc123" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

Create and update responses carry a non-blocking `warnings` array — for example when a PSTN member also belongs to another group — so a caller can surface "this number is already in group X" instead of rejecting an intentional overlap.

***

## 7. Troubleshooting

| Symptom                                    | Likely cause                                                                         | Check                                                                                     |
| ------------------------------------------ | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| Call falls straight to voicemail           | The route's `ring_group_id` points at a deleted group, or `config` carried the id    | Re-save the route with `ring_group_id` as a sibling field; confirm the group still exists |
| Only one phone rings                       | Strategy is `longest_idle` / `fewest_calls` and one member dominates                 | Switch to `simultaneous`, or trim the roster                                              |
| Every phone rings, nobody sees it          | Members are PSTN numbers and the leading `+` was dropped                             | Fix the member to full E.164; PSTN members need `+`                                       |
| Save is disabled in the modal              | Roster is empty, a member doesn't resolve, or a cycle would form                     | Read the inline reason under the member editor and fix the named member                   |
| Group rings but the "wrong" member answers | `round_robin` / `longest_idle` rotation                                              | Expected — rotation moves the starting member each call                                   |
| Caller waits, then drops                   | Ring timeout longer than caller patience                                             | Lower `ringTimeoutSec` or add a fallback destination                                      |
| 409 on create                              | Name already exists in your org                                                      | Rename or update the existing group                                                       |
| 422 on create/update                       | Member rejected — unknown SIP credential, malformed PSTN, self-reference, or a cycle | The response names the offending member                                                   |

### Worked example: after-hours pilot desk

You run a support line Mon–Fri, but after hours a fixed set of phones should ring: the night manager's deskphone, their cell, and — if nobody answers — a shared voicemail box.

1. In **Voice → Ring groups**, create `After-hours desk` with strategy `simultaneous`, ring timeout `20`, and three members: the deskphone's SIP username, the manager's PSTN cell (`+12025550123`), and (only if useful) another ring group such as `Escalation`.
2. In **Numbers → *support line* → Routing**, set the primary route to that group with fallback `voicemail` pointing at the department box.
3. Add a `business_hours` window to the route so after-hours callers hit the group while daytime callers hit the queue.
4. Place a test call after hours and watch the **Calls** log — you should see all three destinations ring and the one that answered.

Two groups with overlapping members (e.g. two after-hours desks ring the same cell) are allowed; the pre-save warning just tells you the overlap exists, so confirm it's intended.

***

## Related references

* [Paging groups, ring groups & call park (overview)](/voice/paging-ring-groups-call-park)
* [Voice queues](/guides/voice-queues)
* [Inbound number routing](/guides/inbound-number-routing)
* [Voicemail boxes](/guides/voice-voicemail-boxes)
* [Number assignments (fallback ladder)](/guides/number-assignments)
