Assignment & Routing
How conversations get an owner — manual assignment, automatic distribution, assignment rules, teams, and the capacity limits that keep queues sane.
Assignment records who owns a conversation. One person at a time, or nobody.
It matters more than it looks. An unowned conversation is one everybody assumes someone else is handling, and the difference between a team that answers in ten minutes and one that answers in two days is usually a routing problem, not an effort problem.
A conversation must be handed off before it can be assigned. While the bot owns it there is no assignee picker — see Ticket States. If you use an external help desk, assignment happens there instead and none of this page applies.
The three ways an assignee is set
Someone assigns it. From the conversation sidebar, in bulk from the conversation list, or as a macro action.
An agent replies. Replying assigns the conversation to whoever sent the reply — even if a colleague had it. Whoever is talking to the customer owns the conversation.
An agent closes it. Closing assigns the conversation to whoever closed it, if it wasn't already assigned to them.
Admin accounts are excluded from the last two, so an admin can answer a question or tidy the queue without silently taking ownership of everything they touch.
If your workspace has automatic distribution switched on, there is a fourth: conversations are assigned as they're escalated, before anyone touches them.
When an assignee is removed
Each organization chooses what happens to a conversation when its agent stops working:
| Ownership | Behaviour |
|---|---|
| Keep with agent (default) | The assignee survives closing, reopening, snoozing and going offline. Only a person or a macro reassigns it. |
| Release when offline | When an agent goes offline, their open conversations return to the unassigned pool. |
Keep with agent means a conversation that comes back three weeks later comes back to the same person. That's usually what you want, since they have the context, but it does mean an agent who leaves takes a queue with them unless someone reassigns it.
Release when offline gets work moving when someone logs off, at the cost of losing the continuity of one person owning a thread. It works like this:
- Delay. An agent must stay offline for the release delay (30 minutes by default) before their conversations are released, so a short break doesn't empty their queue. Coming back online resets the clock. With a delay of 0, conversations are released within about a minute.
- Archived users are released straight away, whatever the delay.
- Open conversations only. Closed conversations keep their assignee, so per-agent reporting still works. Snoozed conversations stay assigned until they wake up.
- Reopened conversations are covered. If a customer reply reopens a conversation, or a snooze wakes up, while its agent is still offline, it's released on the next check.
- Only agents are released. Conversations held by people who aren't marked as agents, such as a manager who replied, stay with them.
- Every release is logged on the conversation's timeline, with the reason (for example, "agent inactive in the dashboard for 30+ minutes").
Assigning on reply and on close works the same under both policies. Released conversations wait in the unassigned pool for someone to pick them up, or for automatic distribution if the business has it switched on.
Ownership and the release delay apply to the whole organization. Manage them with Copilot, MCP or the REST API.
Automatic distribution
Each business runs one of three policies:
| Policy | Behaviour |
|---|---|
| No auto-assignment | Nothing is distributed. Agents pick work up themselves. |
| Round-robin | Each new conversation goes to the next available agent in turn. |
| Balanced | Each new conversation goes to whoever currently has the fewest open ones. |
Balanced is the better default for most teams. Round-robin distributes evenly by count, which drifts out of fairness as soon as some conversations take much longer than others; balanced self-corrects because a slow conversation keeps counting against its owner until it's finished.
Distribution runs when a conversation is handed off. It never reassigns a conversation that already has an owner.
Eligibility
Only online agents receive work. When working hours are on, an agent also needs a working-hours schedule to receive work. An agent also needs room under their capacity limits.
If nobody is eligible, the conversation stays unassigned until someone picks it up or has room:
- When an agent closes a live chat, the oldest waiting chat on that business goes straight to them if they have room.
- In organizations that release conversations from offline agents, a sweep retries waiting conversations about once a minute, highest priority first, then longest waiting. When nobody in a pool (a business, the team a rule routes to, and a channel) has room, the sweep moves on to other pools instead of waiting on that one.
Capacity
Capacity decides how much work automatic distribution hands a single agent. Limits live in capacity profiles:
- Every organization has a Default profile. Agents without a profile of their own use it.
- You can give any agent a different profile, for example one for a chat team and one for a ticket team. Each agent has exactly one profile.
- A profile holds a list of limits and an optional end-of-shift taper. An agent receives a new conversation automatically only when every limit that applies to it is below its maximum.
Limits
Each limit has these parts:
| Part | Meaning |
|---|---|
max | How many open conversations the agent can hold before the limit stops new ones. 0 means never. |
counts | Which of the agent's open conversations count toward max, by channel. |
appliesTo.channels | Which new conversations the limit holds back, by channel. |
appliesTo.businessIds | Optional. Only hold back conversations from these businesses. Leave it out for every business. |
name | Optional label, shown when the limit is what stops an agent. |
Channels are written as "all", { "only": [...] } or { "except": [...] }. A conversation's channel is the channel of its latest message, the same one assignment rules match on. Use except when a limit should also cover channels added in the future.
Usually counts and appliesTo name the same channels: "at 3 open chats, no more chats". They can differ. A limit that counts every channel but only applies to email means "an agent busy with 5 conversations of any kind gets no new emails", which keeps chat agents free for chats.
For example, a team that answers chats and also helps with email, at most 3 chats and 7 emails each:
[
{
"name": "Chats",
"max": 3,
"counts": { "only": ["web", "messenger", "instagram", "whatsapp"] },
"appliesTo": {
"channels": { "only": ["web", "messenger", "instagram", "whatsapp"] }
}
},
{
"name": "Emails",
"max": 7,
"counts": { "only": ["email"] },
"appliesTo": { "channels": { "only": ["email"] } }
}
]An agent holding 7 emails still receives chats, and an agent with 3 chats still receives emails.
What counts as open
A conversation counts toward an agent's limits while it is assigned to them, handed off, not closed, not snoozed and not spam. Counts span every business in the organization: a limit of 3 means 3 in total, not 3 per business.
Snoozing frees capacity. When a conversation is waiting on the customer, snooze it. A customer reply or the end of the snooze brings it back, and it counts again from then.
What limits don't stop
Limits only hold back automatic distribution. These still assign as usual:
- manual assignment, and assigning on reply or on close
- assignment rules that target a specific person
- a conversation coming back to its owner, for example after a customer reply
An agent over a limit keeps their conversations and simply receives no new automatic ones until they're under it again.
End-of-shift taper
When working-hours availability is on, a profile can scale an agent's limit down as their shift ends, so nobody is handed a pile of new work ten minutes before they log off. The taper counts every open conversation and holds back every channel.
| Field | Default | Meaning |
|---|---|---|
fullShiftLimit | 45 | Limit while more than taperStartsHoursBeforeShiftEnd hours of shift remain. |
taperStartsHoursBeforeShiftEnd | 3 | When the taper starts. |
conversationsPerRemainingHour | 15 | After that, the limit is this many per remaining hour, rounded. |
minimumLimit | 4 | The tapered limit never drops below this. |
New profiles get these defaults unless you set others. Set endOfShiftTaper to null to turn it off.
Where the old per-business cap went
Each business used to have a max open tickets setting. Each organization's Default profile carries those over unchanged: one limit per cap value, counting every open conversation and holding back every channel except email, for exactly the businesses that had that cap. Organizations without caps start with an empty Default profile.
Who counts as available
The same definition decides who receives auto-assigned work and when conversations are released from offline agents. An agent is offline when any of these applies:
- They marked themselves unavailable. This always counts.
- They're outside their working hours, when working-hours availability is on. Agents without a schedule are never considered off shift, but they also don't receive auto-assigned work while this is on.
- They have no Octocom dashboard open, when activity-based availability is on. An agent stays active while a dashboard tab is open and visible. They become inactive about 90 seconds after closing their last tab, or about 5 minutes after it was hidden behind other windows or tabs.
Archived users are always offline. Users who aren't marked as agents are never assigned work automatically and never released.
Working-hours and activity-based availability apply to the whole organization.
Assignment rules
Policies decide who among the eligible. Assignment rules decide which pool is eligible in the first place — this is how a conversation reaches the right team rather than just the next free person.
A rule is a set of conditions plus a target. Conditions can match on:
business · channel · priority · tags · email inbox · topics · language · sentiment · collected data values
All conditions on a rule must match. Rules are evaluated in priority order and the first full match wins. Rules with the same priority have no guaranteed order, so give rules that can match the same conversation different priorities.
A conversation no rule matches can go to any agent in the organization. If a business has auto-assignment on but no rule covers it, its conversations go to whichever available agent has the most room, whatever their team. Before turning on auto-assignment for a business, add a rule that routes it to its team.
A rule can target:
- A specific person — they're assigned directly, and the distribution policy is skipped entirely. Use this when one named individual must handle something, which is the point of an individual rule.
- A team — the candidate pool narrows to that team, then round-robin or balanced picks the agent from it.
Rules see analysis results
Conversation analysis runs before assignment, so topics, sentiment, language and collected-data values are already computed when rules evaluate. You can route on "language is German" or "sentiment is angry" without writing anything.
Tags applied by a bot action before the handoff are also in place by then — which is the mechanism behind department routing. See Human Escalation for the pattern.
Teams
A team is a named group of people. Teams do three things:
- Scope assignment rules — route a category of work to a group rather than an individual.
- Scope views — a team view appears in that team's folder and only for its members.
- Organize the sidebar — each team gets its own section.
By default people see only the teams they belong to. The view all teams permission lifts that, for supervisors who need the whole picture.
Teams are worth creating as soon as different groups of people handle genuinely different work — by language, by brand, or by tier. Below that, one pool and a balanced policy is simpler and works fine.
Per-agent settings
Each user carries settings that feed the routing above:
- Working hours — a weekly schedule in the agent's own timezone, with as many slots per day as you need. Alongside it you can record time off for holidays, and set a one-off offline until or overtime until override when someone leaves early or covers a late shift. Only used when working hours are enabled for the organization.
- Marked as unavailable: a switch each agent controls themselves, from their avatar menu at the bottom of the navigation. It takes them out of distribution without touching their schedule, which makes it the right tool for a sick day or heads-down time. When conversations are released from offline agents, it releases theirs too, so agents shouldn't leave it on while they work. An agent who is outside their working hours shows as unavailable regardless.
- Agent — whether the person receives conversations at all. Managers who only read reports don't need it.
- Archived: removes a departed teammate from distribution while keeping their history intact. When conversations are released from offline agents, their open conversations are released immediately.
- Capacity profile: the limits on how much automatic work the agent receives. Agents without one use the organization's Default profile.
Choosing a setup
| Situation | Suggested setup |
|---|---|
| Small team, everyone handles everything | No auto-assignment; work from a shared queue |
| Team large enough that "who's taking this?" is a question | Balanced, no rules |
| Different languages or brands handled by different people | Balanced + teams + rules on language or business |
| One person must own a category (wholesale, legal, VIP) | An individual rule for that category, balanced for everything else |
| Agents on fixed shifts across timezones | Enable working hours; the end-of-shift taper is on by default |
| One team handles both chat and email | A capacity profile with separate chat and email limits |
| Live chat where response time matters | Enable activity-based availability |
| Queues shouldn't wait for an agent who logged off | Release when offline, with activity-based availability or working hours |
Start simpler than you think you need. Rules are easy to add once you can see where the work actually goes, and a routing setup nobody understands is worse than none.
Managing assignment settings
Ask Copilot to review or change these settings, for example "Unassign tickets from agents who have been offline for 30 minutes", "Send Osuren emails to the CS Ticket Support team", "Give the chat team a limit of 3 chats and 7 emails each" or "Why is this ticket still unassigned?". The same capabilities are available over MCP and the REST API.
Assignment settings also hold each business's customer waiting alert as businesses[].customerWaitingAlertMinutes: whole minutes from 1 to 1440, or null to turn it off. Changing assignment settings through MCP needs the modify-settings permission.
MCP tools
| Tool | Arguments | Result |
|---|---|---|
get_assignment_settings | None | Complete settings |
update_assignment_settings | patch | Complete updated settings |
list_agent_availability | None | Each agent's availability, load against their capacity limits, and pending release |
list_capacity_profiles | None | Every profile with its limits, taper and agents |
create_capacity_profile | name, rules, optional endOfShiftTaper | The new profile |
update_capacity_profile | profileId, patch | The updated profile. rules replaces all limits; isDefault: true makes it the default |
archive_capacity_profile | profileId | Refused for the default profile or while agents use it |
set_agent_capacity_profiles | profileId (or null for the default), userIds and/or teamIds | The users changed. A team sets each current member once |
list_assignment_rules | Optional businessId | Rules in evaluation order. businessId keeps only rules that can match that business |
create_assignment_rule | name, assignTo, conditions, optional priority, isActive | The new rule |
update_assignment_rule | ruleId, patch | The updated rule. conditions replaces all conditions; isActive: false pauses the rule |
delete_assignment_rule | ruleId | The deleted rule |
explain_conversation_assignment | conversationId | Who would receive the conversation now, the matched rule, and each agent's availability and limits |
MCP also requires the selected organizationId, as with other organization-scoped tools. Reads work for read-only callers; updates require write access.
Rules
assignTo is { "type": "team", "teamId": "..." } or { "type": "user", "userId": "..." }. Each condition has a type, an operator (containsSome or containsNone) and values:
type | values |
|---|---|
business | Business ids |
channel | Channel names, such as email, web, messenger, instagram, whatsapp, phone-call |
email | Email inbox ids, the inbox the conversation's email arrived in |
tags | Tag ids |
priority | "null" (no priority), "1" (low), "2" (medium), "3" (high) |
topics | Topic names |
language | ISO 639-1 codes, such as en or de |
sentiment | Strongly Positive, Slightly Positive, Neutral, Slightly Negative, Strongly Negative |
dataCollection | key:value, with colons removed from the key and the value |
Business, tag and inbox ids must belong to the organization. For example, to send one brand's emails to a team:
{
"name": "Osuren emails",
"assignTo": { "type": "team", "teamId": "TEAM_ID" },
"priority": 10,
"conditions": [
{
"type": "business",
"operator": "containsSome",
"values": ["BUSINESS_ID"]
},
{ "type": "channel", "operator": "containsSome", "values": ["email"] }
]
}A rule applies to the next assignment. Conversations already assigned keep their agent.
Settings
| Field | Meaning |
|---|---|
ownership.policy | keepWithAgent or releaseWhenOffline. |
ownership.releaseDelayMinutes | Whole minutes from 0 to 1440 an agent must stay offline before release. Archived users are released immediately. |
availability.workingHours | Agents with a schedule are offline outside it. |
availability.dashboardActivity | Agents are offline when they have no open, visible dashboard tab. |
offlineTriggers | Read-only. What makes an agent offline under the current settings: markedUnavailable, outsideWorkingHours, inactive, archived. |
businesses[] | Each active business's autoAssignment: none, roundRobin or balanced. |
capacity | Read-only. The default capacity profile's id and name. Limits are managed with the capacity profile tools. |
Only fields supplied in patch change, and only the businesses listed in patch.businesses. Empty patches and unknown fields are rejected. For example, to release conversations from agents who have been inactive for 30 minutes:
{
"organizationId": "YOUR_ORGANIZATION_ID",
"patch": {
"ownership": { "policy": "releaseWhenOffline", "releaseDelayMinutes": 30 },
"availability": { "dashboardActivity": true }
}
}Switching to releaseWhenOffline takes effect on the next check, about once a minute: agents who are already offline for longer than the delay have their open conversations released straight away. Check list_agent_availability first to see who holds what. For each agent it returns online, offlineReasons, offlineSince, receivesAutoAssignment, openConversations and, when conversations will be released, releaseAt. Archived users who still hold open conversations are included.
maxOpenTickets is no longer accepted in patch.businesses; the error points to capacity profiles.
Successful changes record before and after settings in configuration history, with Copilot, MCP or API attribution. Assignment rule changes, capacity profile changes and agent profile assignments are recorded the same way.
REST API
Authenticate with X-API-Key:
| Method | Path | Input |
|---|---|---|
GET | /rest/v1/assignment/settings | No body |
PATCH | /rest/v1/assignment/settings | Settings patch directly as the JSON body |
GET | /rest/v1/assignment/agents | No body |
GET | /rest/v1/assignment/rules | Optional businessId query parameter |
POST | /rest/v1/assignment/rules | name, assignTo, conditions, optional priority, isActive |
PATCH | /rest/v1/assignment/rules/{ruleId} | Rule patch |
DELETE | /rest/v1/assignment/rules/{ruleId} | No body. Deletes the rule |
GET | /rest/v1/assignment/capacity-profiles | No body |
POST | /rest/v1/assignment/capacity-profiles | name, rules, optional endOfShiftTaper |
PATCH | /rest/v1/assignment/capacity-profiles/{profileId} | Profile patch |
DELETE | /rest/v1/assignment/capacity-profiles/{profileId} | No body. Archives the profile |
PUT | /rest/v1/assignment/agent-capacity-profiles | profileId (or null), userIds and/or teamIds |
GET | /rest/v1/assignment/conversations/{conversationId}/explanation | No body |
Responses wrap the result in { "data": ... }. REST uses the same settings and validation as MCP. Invalid input returns 400. A business, team, user, tag, email inbox, rule, profile or conversation outside the organization returns 404. Updating an archived business, reusing a profile name, or archiving the default profile or one agents still use returns 409.