Skip to content

Product · Queues

Separate teams. Separate rules. One number.

Sales, Support and Billing behind one published line, each deciding for itself who is eligible, what a caller hears while they hold, and when the waiting stops. Adding a fourth is a setting, not a build.

Named queues over one shared routerEligibility from membership and skillsHold music, announced wait, a callback

The queue

A queue is a rule, not a room.

Three named queues look like three places for a call to sit and wait. They are not. Each is a row you wrote (a name, a priority, the skills it requires, the people in it, and what plays while somebody holds), and underneath, all of them are one waiting line with one rule per queue written over it.

Which is why the fourth queue costs nothing. Naming one adds a row and one routing rule beside the rules already there; it does not stand anything new up for the call to travel through. A queue invented on a Tuesday afternoon behaves exactly like the three that have been running for a year, because it is the same machinery being asked a different question.

The rules are read in order and the first match wins, which is why there are three kinds. A call to somebody’s own direct line is matched first and only ever rings that person. Then the named queues. Then a catch-all, for a call that named none, and that one lands in the fallback queue every organization gets, which describes itself: Everyone. Calls that do not name a queue arrive here.

Every organization’s rules live in that one router, so saving yours rewrites your block and leaves everybody else’s in the order it found them. That is not tidiness. Getting it wrong is an inbound outage for a customer who changed nothing.

Where the queue gets chosen
Queues
SalesPriority 40 · needs french2 waitinglongest 0:41
SupportPriority 60 · needs tier-25 waitinglongest 3:08
BillingPriority 20 · no skill requiredEmptylongest ·

The priority, the skills a queue requires and the wait are the fields the queue manager actually shows. The counts are a live reading, not somebody’s real numbers.

Eligibility

Who the call can be offered to.

Being in the queue is one half of it. The other half is skills, and they are ANDed rather than pooled: every skill the queue requires has to be on the person, not one of them. A caller who pressed 2 for French does not reach somebody who does not speak it, and that holds because the router is asking about the person rather than because the flow was written carefully.

Skills are words you invent (french, billing, tier-2), typed onto the person and onto the queue. There is no catalogue to pick from and there are no levels. A flat list of words is a thing an office manager can keep true; a competency matrix is a thing that goes stale in a fortnight and then routes calls with last spring’s answer.

Adding somebody to a queue whose skills they lack is allowed, and the row says so as you tick it: it names the skill they are missing. A member who can never be offered a call from a queue they are in is indistinguishable from a routing bug, and the only cheap moment to catch it is while you are still looking at the checkbox.

An empty queue says the same thing louder. It reads, in red, that calls sent there will wait for nobody.

Priority orders the calls, not the people. A call from a higher-priority queue is offered ahead of one that has been waiting longer, which is the behaviour you want for the line your best customers were given, and is not the same thing as jumping somebody’s turn at answering.

Only somebody who has made themselves available is offered anything. Somebody who has sent their calls to their own phone still is, and the forwarded leg lands in the same conference as a softphone would, so a queue call reaching somebody on the road keeps hold, transfer and recording rather than becoming a bare forwarded call with none of them.

Choosing who is in a queue is a permission of its own, separate from being able to see the queues at all. The reason is written next to it in the code: deciding membership is deciding whose phone rings.

The permission that governs this

Waiting

What the caller hears meanwhile.

A queue can carry a flow of its own for the wait, and it is a different kind of program from the one that answered the call. The phone network asks for it again from the top, over and over, for as long as the person holds. There is nowhere to keep a place in it, and exactly one thing survives from one loop to the next: how long they have now been waiting.

That single number is what makes the useful thing sayable (after ninety seconds, offer them a callback), and it is why the waiting flow runs on its own executor instead of sharing one with the flow that greeted them.

A waiting document honours only a handful of instructions and silently drops the rest. Not an error: the block simply never happens. So publishing checks the blocks against that list, rather than letting a caller discover it as thirty seconds of nothing.

Alongside those three: a message of your own, a pause, one branch on how long they have waited, and a block that takes them out of the queue entirely.

Hold music

Your own audio, or the standard hold music if you name none. It loops, because a waiting caller leaves by being answered rather than by the track finishing, and it is bounded per pass, so one loop cannot run for an hour.

Announce wait time

Reads the wait the router has measured and says it in words: about two minutes, or less than a minute. Never a count of seconds, and nothing at all when there is no usable figure. A caller times their patience by that sentence, so a wrong one is worse than none.

Offer a callback

Press 1 and the number the call arrived from is taken down, confirmed out loud, and the caller can put the phone down. Press nothing and they keep holding: in a waiting document, silence is not a refusal, it is somebody who has not decided yet.

A callback offer is a promise, so the half that keeps it is a job rather than an intention. It rings the person back, and when they answer they go into the queue the way an inbound call does: the same offer window, the same fall through to voicemail if nobody takes it, the same controls once somebody does.

It tries three times and then stops, because a number that never answers is not an outage. It gives up after a day, on the reasoning that the person has moved on and a call out of nowhere tomorrow is worse than no call. It refuses to dial an emergency number back. And one request per call means a retried instruction cannot ring somebody twice.

It counts as kept when the person picks up, not when the network accepted the dial. Those are not the same event, and treating them as one is how a callback that rang out gets recorded as delivered.

A queue with no flow of its own plays the standard hold music. That is the default and it stays the behaviour for any queue nobody configures, and an in-queue flow cannot be attached to a queue until it has been published, because a silent fallback at call time is a worse discovery than a refusal now.

Hours

Every location keeps its own hours.

Opening hours are not one company-wide setting here. They are named schedules (one per site, or per team, whichever matches how you actually close), each with its own timezone, its own week, and its own dated holidays that can name themselves so a caller hears which one it is.

The zone is applied when the question is asked rather than stored as an offset, which is the only way nine-to-five stays nine-to-five through March. A shift that runs past midnight is a range like any other, not a special case somebody has to remember.

A block in the flow names one schedule and branches four ways from it: open, a holiday, an emergency, or simply closed. One row answers all four, so “are we open” cannot have a different answer on different branches.

And it happens inside the flow, before there is a call for anybody to be offered. A caller at nine in the evening hears your closed message. They do not spend the offer window in a queue nobody is watching.

A schedule with nothing filled in means open. Every other default would have taken somebody’s phone line down on the day it shipped, silently, as a reward for not having finished configuring it.

The honest edge of that: hours live in the flow, so a number not bound to a flow rings around the clock. It is the design rather than an oversight, but it is also the first thing to check when a line answers at midnight.

Emergency

One switch that outranks the calendar.

A flood, a power cut, a closure nobody could have put in a calendar. There is a switch on the schedule for exactly that, and it is read before the holidays, before the week’s hours, and before the rule that treats an unfilled schedule as open. That last ordering is the one that matters: the organization that most needs to say we are shut, right now is often the one that never finished filling the hours in.

It is a flag rather than an edit to your hours, and deliberately so: it must not require publishing a flow at the moment somebody is standing in a stairwell with a phone. It keeps when it went on and who turned it on, and that record outlives the account of whoever did.

It does not take the line dark, either. Every flow naming that schedule takes its emergency branch, so what callers hear is still something you wrote: a different message, a different queue, straight to voicemail. Switching it off puts everything back, and needs no publish in that direction either.

Overflow

When nobody answers.

Waiting is bounded. A call is offered for thirty seconds, and if nobody takes it the router cancels the offer and the caller is brought back into your flow on its overflow branch. What happens there is yours: voicemail, a different queue, a message and a goodbye.

Accepting a callback leaves through the same door. The instruction that ends the wait continues at the very next one after it, and that next one is put there on purpose: without it, the branch designed to catch an overflow would be unreachable by the one route built to reach it, and the call would just end.

Nothing is dropped quietly on the way. A published flow that names a queue somebody has since deleted sends the call to the fallback queue and records why, because a caller reaching a person who was not the intended person is better than a caller reaching nobody.

And a caller on hold never hears an error. An unpublished waiting flow, a deleted queue, a graph that will not parse: all of them fall back to hold music, which is what the caller would have heard anyway.

Follow one call, ring to record

What this does not do

This routes calls. It does not run a workforce. Nothing here works out how many people should be on Support at four in the afternoon, nothing measures anybody against a plan they were handed, and no score is kept per person. Queue membership and skills are settings somebody writes because they know the team, not the output of a forecast. And if what you need is the other thing, this is the wrong shape of product rather than a smaller version of it.

The live reading of how many are waiting and how long the longest has waited belongs to the organization as a whole rather than to each named queue, and the figure an announcement quotes is measured the same way. With one queue those are the same number. With three busy ones it is an average across all of them, and a caller in the quiet queue hears the busy queue’s wait.

A maximum wait can be typed onto a queue and saved, and it does not yet decide anything: the thirty-second offer is what ends a wait, on every queue. It is a setting waiting for the code that enforces it, and until that lands the number to plan around is thirty seconds.

There is also no rule you can write for how offers are spread between the people who qualify. Priority orders the calls; it does not take turns among the team, and nothing balances a day’s calls evenly across a queue’s members.

A queue is written to our own database first and mirrored into the router immediately after. If the router is briefly unreachable the queue exists and its routing rule can lag behind it, which is fixed by saving it again and is logged loudly enough that we see it first. Refusing your edit because somebody else’s service was slow for four seconds would be the worse failure.

If one of those is the thing that would actually stop you, say so early. I would rather tell you where it really is than have you find it in week three.