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

# Voice teams: create, staff, and route to them

> Create agent teams from Voice → Teams, manage members, target a team with the assign_team routing action, and audit the group with supervisor Team Listen.

A **team** is a named group of members in your organization. Two shipped surfaces consume the team model: the routing-rule action `assign_team`, which spreads inbound conversations across the team instead of leaving them unassigned, and supervisor **Team Listen**, which samples one live call from the team roster for group monitoring. Both share the same roster, so the members you manage on one screen drive assignment and QA sampling everywhere.

This guide walks the operator loop: create a team, manage its members, wire a routing rule to it, and monitor the result. The full endpoint vocabulary and the permission model behind it are defined in [Roles, teams, and permissions](/concepts/roles-teams-permissions); this page is the operator's walkthrough.

**Base path:** `/api/v1/teams`

**Scope:** reads (list teams, list members) admit any member of the organization — the inbox's "Assign to team" picker and the Team Listen group list work for agents and supervisors, not just admins. Writes (create, edit, delete, add/remove members) require the `team:invite` permission: on the built-in roles that means owner or admin; on a custom role, the role's grants must include the "Invite team members" capability.

***

## 1. Create a team

Open **Voice → Teams** in the dashboard. The page lists every team in the organization with its name, description, active state, and member count.

1. Click **Create team**.
2. Enter a **name** (required, up to 120 characters — pick a routing-meaningful name like "Billing support" or "LATAM pod", since routing rules reference the team by it) and an optional **description** (up to 500 characters).
3. Set the **active** flag. Routing to a deactivated team never assigns: the `assign_team` action only considers teams whose `active` flag is on, and a routing rule pointing at a deactivated team falls back to the no-members behavior in Section 3.
4. Save. The team appears in the list sorted by name.

To rename, redescribe, or toggle the active flag, open the **Edit** action on the team's row — the same modal handles create and update. **Delete** opens a confirmation step; deleting a team removes its members with it and cannot be undone. If a routing rule still targets a deleted team, incoming conversations hit the safe fallback in Section 3 — re-point or delete the rule before you delete the team.

Over the API, the same operations map to:

```bash cURL theme={null}
# Create
curl -X POST "https://api.orbit.devotel.io/api/v1/teams" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Billing support", "description": "Billing and payments queue", "active": true }'

# Update (rename / redescribe / toggle active)
curl -X PATCH "https://api.orbit.devotel.io/api/v1/teams/team_abc123" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Billing and payments", "active": true }'
```

Team names are unique per organization — reusing one returns `409 CONFLICT`. Each organization is capped at 200 teams; over the cap, creation returns `409 LIMIT_EXCEEDED`. Every create, update, and delete is written to your audit log (`teams.created` / `teams.updated` / `teams.deleted`).

## 2. Manage members

Open the **Members** action on the team's row. The dialog lists the team's members and adds or removes them by user — the user must already be a member of your organization (invite them first from Settings → Team); the team links an existing org user id, it does not create one.

1. Pick a user from the organization roster and add them. Adding the same user twice returns `409 CONFLICT`.
2. Remove a member with the remove action next to their name.

The roster is additive: a member of a deactivated team is unaffected by other teams they belong to, and removing them here removes only this membership.

Over the API:

```bash cURL theme={null}
# Add a member
curl -X POST "https://api.orbit.devotel.io/api/v1/teams/team_abc123/members" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "user_id": "user_2bFzq9W" }'

# Page the member list (keyset pagination)
curl "https://api.orbit.devotel.io/api/v1/teams/team_abc123/members?limit=25" \
  -H "X-API-Key: dv_live_sk_your_key_here"
```

Member listing is keyset-paginated (`created_at`, then `id`): read the opaque `cursor` from the response's pagination metadata to fetch the next page, up to 100 per page. The response also carries a `total` badge capped at 1,000 — a team at the cap reads `total: 1000` with `total_capped: true` (render "1,000+"). Each membership row carries the picked member's `last_assigned_at` timestamp, which the routing picker uses for round-robin fairness (Section 3).

## 3. Route inbound conversations to a team

The routing-rules engine assigns a conversation to a team once the rules and the team both exist. Rules evaluate in priority order and AND-combine their conditions; the full condition/action reference is in [Omnichannel queue routing](/guides/omnichannel-queue-routing).

### Wire the rule

From the inbox routing-rules builder (or the API), create a rule whose action is `assign_team` with the team as its target:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/inbox/routing-rules" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Billing emails → Billing support team",
    "priority": 10,
    "conditions": [
      { "kind": "channel", "value": "email" },
      { "kind": "contact_attribute", "key": "topic", "operator": "equals", "value": "billing" }
    ],
    "actions": [
      { "kind": "assign_team", "target_id": "team_abc123" }
    ]
  }'
```

### How the pick is made

When the rule fires, the platform picks one **active** member of the team by a load-balancing ordering:

1. fewest currently-open conversations assigned to them (open-count ascending),
2. tie-break on the last-assigned time, oldest first (a member never picked yet wins), then
3. user id, for a deterministic order on perfect ties.

The conversation is assigned to the picked user — a real user id, so the inbox assignee, filters, and reporting all render it as a person, exactly like a manual assignment. The platform then bumps that member's `last_assigned_at` so the next assignment favors the rest of the roster. If the organization configured per-channel concurrency caps (Settings → Team → Channel concurrency caps), members already at their ceiling on the conversation's channel are skipped — and if every active member is at their cap, the conversation is left unassigned rather than overshooting the cap.

### Empty team, deactivated team: the safe fallback

If the rule targets a team with **no active members** — including a deactivated team, a team whose members were all removed, or a team that no longer exists — the action refuses to mis-assign. The conversation is left unassigned and a system-authored internal note is posted on its timeline saying the team-based assignment could not resolve. Fix the rule roster the same way: staff the team, reactivate it, or re-point the rule.

## 4. Supervisor Team Listen

Once a team has members, a supervisor can monitor the group as a group instead of a per-call wallboard pick. This is the QA-sampling verb Genesys/NICE-class CCaaS consoles ship, and it reuses the team's roster.

On **Voice → Monitoring**, click **Team Listen**:

1. Pick a team from the list. Only teams with at least one member appear; a team with no members cannot be sampled.
2. Choose a rotation:
   * **Oldest call** — attach to the team's longest-running active call, the default. QA tends to care about long-running calls, which are likely escalations.
   * **Random** — attach to any active call from the team, uniformly.
   * **Least recently sampled** — attach to the agent whose calls have gone the longest without being sampled (or never sampled), so coverage spreads fairly across the roster.
3. The platform picks one active call from the team roster and attaches your supervisor leg in **listen-only** mode — the same surface as the per-call silent monitor. The sampled call and agent are identified on your console.

Every sample is recorded in your audit log as `voice.supervisor.team_monitor`, distinct from the per-call `voice.supervisor.silent_monitor`, so compliance review can separate targeted call monitoring from group sampling. Team Listen requires a roster on the team; if no member of the team currently has an active call, there is nothing to sample. The full supervisor console is covered in [Supervisor live monitoring — voice](/guides/supervisor-live-monitoring-voice).

## 5. Limits and semantics

* **Per-organization team cap:** 200 teams. The list endpoint returns at most that many, sorted by name; creation beyond the cap returns `409 LIMIT_EXCEEDED`.
* **Member pagination:** keyset over (`created_at`, `id`) with an opaque cursor; page size defaults to 25 and clamps at 100.
* **Member-count badge:** the list response's `total` stops counting at 1,000 members and flags `total_capped: true`; render "1,000+" instead of a precise count.
* **Team deletion:** removes the team's member rows with it (the reverse link from member → team is app-managed to keep tenant schemas conservative). Routing rules that still point at the deleted team fall back to the no-members behavior in Section 3 — clean up the rule before you clean up the team.
* **Pre-migration tenants:** the read endpoints degrade to empty lists rather than erroring, so a tenant whose schema predates the teams tables still serves the picker surfaces without breaking the inbox or the monitoring console.

## Related guides

* [Roles, teams, and permissions](/concepts/roles-teams-permissions) — the endpoint and permission reference this page builds on.
* [Omnichannel queue routing](/guides/omnichannel-queue-routing) — the routing-rules engine, conditions, and actions (including `assign_team`).
* [Inbox setup](/guides/inbox-setup) — wire the digital channels whose conversations your rules then route.
* [Supervisor live monitoring — voice](/guides/supervisor-live-monitoring-voice) — the supervisor console Team Listen lives in.
