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

# Plan per-agent channel concurrency caps

> How the per-agent, per-channel concurrency matrix on Settings → Team works, how to pick cap numbers for voice seats, inbox handle times, and SMS bursts, and how to read cap-exhaustion signals when an agent looks idle but is capped.

# Plan per-agent channel concurrency caps

A concurrency cap limits how many open interactions of one channel a single agent can be routed at the same time. Caps are set per agent and per channel on the **Channel concurrency caps** card under **Settings → Team**. This guide covers the model, how to pick numbers per channel, how to configure caps in the dashboard and over the API, and how to operate them on a live floor.

For who is allowed to act as an agent at all, see [agent identity and governance setup](https://docs.orbit.devotel.io/guides/agent-identity-governance-setup.md). For anomalies that are not cap-related, see the [agent fleet debugging playbook](https://docs.orbit.devotel.io/guides/agent-fleet-debugging-playbook.md).

## 1. The model

The matrix has one row per team member and one column per channel: SMS, WhatsApp, Email, RCS, Viber, Instagram, Messenger, LINE, Telegram, AI Agent, Voice, Video, Apple Messages, and Web Chat. Each cell holds one value:

| Cell | Meaning |
| - | - |
| Empty | No cap. The agent is eligible for as many simultaneous interactions of that channel as routing offers. |
| `0` | Blocked. The agent is never routed new interactions of that channel. |
| `1` to `1000` | The agent holds at most that many open interactions of that channel. While at the cap, routing excludes the agent from that channel's launchable set. |

An agent with no rows at all is uncapped on every channel. **An empty cap list is fail-open**: a brand-new team routes exactly as it did before the feature existed, and clearing a cell restores "no cap" for that agent and channel.

A cap counts interactions currently open on the agent, not interactions handled today. Closing or resolving an interaction frees one slot immediately; caps do not throttle throughput over time, only simultaneous load.

Caps are per channel and independent. An agent capped at 1 on Voice still takes Email and SMS up to their own cells. Use `0`, not a low number, when the intent is "never route this channel to this agent."

### Interaction with queues, transfers, and macros

* **Queues.** A queue holds conversations until an agent is launchable for them. When every agent who could take a conversation is at cap for its channel, the conversation waits in the queue even though agents appear free on other channels. Queue capacity settings govern the queue itself; agent caps govern assignment out of the queue. If wait times climb while agents sit "idle," check caps before checking staffing.
* **Transfers.** A transfer is an assignment, so it honors the target agent's cap for the conversation's channel. Transferring a conversation to an agent already at cap for that channel is rejected; pick another agent or wait for a slot to free.
* **Macros and bulk actions.** A macro or bulk assign that would claim a conversation for an agent at cap does not override the cap. When two operators run competing claims at once, the claim that would exceed the cap is held back rather than silently over-assigning the agent.

## 2. Pick numbers per channel

Start from the work pattern of each channel, not from a global number.

### Voice: start from seat count

A voice interaction occupies the agent's ears and mouth for its whole duration, so the voice cap is the number of calls the agent can physically hold at once:

* One headset, no hold training: cap `1`.
* Blended agents trained to park calls on hold: cap `2` is a common ceiling; beyond that, caller experience degrades fast.

Never set the voice cap above the number of simultaneous calls the agent's softphone and device can actually carry. If you run an outbound dialer, the dialer's connect rate also feeds this number: with `C` connects per hour and an average connected handle time of `T` minutes, one agent carries roughly `C × T / 60` simultaneous conversations on average. Size the voice cap at or above that figure so connects are not parked waiting for a capped agent, and read [AMD and voicemail drop tuning](https://docs.orbit.devotel.io/guides/dialer-amd-and-voicemail-drop.md) for what drives `C`.

### Inbox and messaging: derive from handle time and target hold time

For channels where an agent works several threads in parallel (Email, Web Chat, SMS, WhatsApp, Messenger), use the active touch time, not the full resolution time. If an agent spends on average `A` minutes of active work per touch, and you want no customer to wait more than `W` minutes between touches, the cap is:

```
cap ≈ W / A
```

Example: `A = 5` minutes per touch and a target of `W = 15` minutes between touches gives a cap of `3`. Pull real `A` and wait figures from your SLA reporting before committing to a number; [reading the inbox SLA report](https://docs.orbit.devotel.io/guides/inbox-sla-report-reading.md) shows where each of those numbers lives.

### SMS bursts: size for the storm, watch the queue

SMS traffic arrives in bursts (a campaign send, an outage announcement) rather than a steady stream. The cap still applies per open thread, so size it for the burst you are willing to let one agent absorb: divide the burst volume you expect per agent by the number of threads an agent can keep inside your first-response target. If the storm exceeds total caps across the team, the overflow waits in queue; that is the cap doing its job, protecting agents from unbounded parallel threads. Raise caps temporarily or move agents off capped-low channels to absorb it (section 4 walks one storm through).

### A safe default shape

| Channel | Starting point |
| - | - |
| Voice | `1`, or `2` for hold-trained blended agents |
| Email | `W / A` from the formula above, typically `3` to `5` |
| Web Chat | `2` to `4`; chat decay is fast, so keep it below Email |
| SMS / WhatsApp / messaging | `4` to `8` for burst tolerance, tuned against first-response targets |
| Channels an agent never works | `0` |
| Everything else | Leave empty until you have evidence |

Leave a cell empty rather than guessing a number. Fail-open with observation beats a wrong cap that silently queues customers.

## 3. Configure caps on Settings → Team

1. Open **Settings → Team** and scroll to the **Channel concurrency caps** card. Rows are your team members; columns are the channels.
2. Enter a whole number in a cell to set a cap, `0` to block the channel for that agent, or clear the cell for no cap.
3. Select **Save changes**. Only changed cells are written; cleared cells revert to no cap. **Reset** discards unsaved edits.

Values must be whole numbers between `0` and `1000`; an invalid cell blocks the save and is marked in the matrix. The card and the endpoints below are restricted to owner and admin roles. Agents and other non-admin roles neither see nor edit the matrix.

### API shape

The same matrix is available over the API. List what is configured:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/settings/agent-channel-caps" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

```json theme={null}
{
  "caps": [
    {
      "agent_user_id": "user_2f8Kd1",
      "channel": "voice",
      "max_concurrent": 1,
      "updated_at": "2026-10-01T09:12:44Z"
    }
  ]
}
```

A missing `(agent_user_id, channel)` row means no cap. Narrow the listing with `?agent_user_id=`, or page with `?limit=` (1 to 200, default 200) and `?offset=`.

Set or change caps in bulk (idempotent upsert, up to 500 rows per call):

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/settings/agent-channel-caps/bulk" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "caps": [
      { "agent_user_id": "user_2f8Kd1", "channel": "voice", "max_concurrent": 1 },
      { "agent_user_id": "user_2f8Kd1", "channel": "sms", "max_concurrent": 6 }
    ]
  }'
```

Clear one cap back to fail-open:

```bash theme={null}
curl -X DELETE "https://api.orbit.devotel.io/api/v1/settings/agent-channel-caps/user_2f8Kd1/sms" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

## 4. Day-ops: read cap exhaustion on the floor

The cap-exhaustion signature is an agent who is seated, ready, and apparently idle, yet receives no new interactions of one channel. On the fleet overview, that agent's row stops appearing in the launchable set for the capped channel even though the agent is present, and the workers chip shows less available capacity than headcount would suggest. When the chip is low but the room is full, caps are the first thing to check.

On wallboards, alarm on queue wait time per channel, not on agent idle time. A cap-induced queue builds while agents look free; a wait-time alarm catches it, an occupancy alarm does not.

### Case study: peak-hour SMS storm with a capped team

A support team of four runs SMS caps of `4` per agent after tuning against their 10-minute first-response target. A campaign send lands 60 replies inside 15 minutes. Total open slots are 16, so 44 threads queue. On the fleet overview every agent shows four open SMS threads and no launchable SMS rows: nobody is idle, nobody is stuck, the matrix is exactly at cap. First response on the queued threads tracks the queue, not the agents.

Two correct responses, in order of blast radius:

1. **Absorb temporarily.** Raise the SMS cells for the two fastest agents for the peak window, then restore them. Caps are per agent, so a temporary raise touches only the people who opted into the burst.
2. **Rebalance.** Move one agent's Email cap down and their SMS cap up for the afternoon. Because caps are independent per channel, shifting capacity between channels is a two-cell edit.

The wrong response is raising every cap to silence the queue: the cap exists to bound simultaneous threads per person, and an agent holding 20 SMS threads answers none of them inside target.

## 5. Troubleshooting matrix

| Symptom | What is happening | What to do |
| - | - | - |
| Agent looks idle but gets no new interactions of one channel | The agent is at cap for that channel; open interactions are holding every slot. | Check the cell on Settings → Team. Raise it, or wait for open interactions to close and free slots. |
| Nothing of a channel ever reaches one agent | The cell is `0`, which blocks the channel entirely. | Set a positive number, or clear the cell for no cap. |
| Transfer to a specific agent is rejected | The target agent is at cap for the conversation's channel. | Transfer to an agent with a free slot, or after the agent's open interactions close. |
| A macro or bulk assign did not claim a conversation | The claim would have exceeded the agent's cap; competing claims are held back instead of over-assigning. | Apply the action to an agent with capacity, or raise the cap first. |
| Conversations queue while agents seem free | Agents are free on other channels but at cap on the queued one. | Read the queue per channel, then the cap matrix per channel (section 4). |
| Save does not apply | A cell holds an invalid value (non-integer, negative, or above `1000`), which blocks the whole save. | Fix the marked cell, then save again. |
| I cleared a cell but the old cap still shows | The matrix re-reads from the server after save; a stale view means the save did not run. | Confirm the save completed (the dirty-state buttons disappear), then reload the page. |

Caps govern routing of **new** assignments only. They never drop or reassign an interaction an agent already holds, and closing an interaction frees its slot immediately.

## Related

* [Agent identity and governance setup](https://docs.orbit.devotel.io/guides/agent-identity-governance-setup.md): who may act as an agent, and the reach table that lists channel caps alongside identity controls.
* [Agent fleet debugging playbook](https://docs.orbit.devotel.io/guides/agent-fleet-debugging-playbook.md): triage for agent anomalies that are not cap-related.
* [Reading the inbox SLA report](https://docs.orbit.devotel.io/guides/inbox-sla-report-reading.md): the handle-time and wait figures section 2 derives caps from.
* [AMD and voicemail drop tuning](https://docs.orbit.devotel.io/guides/dialer-amd-and-voicemail-drop.md): what drives outbound connect rates for the voice cap math.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.