Queue
QueueAction parks the caller in one of the workspace's call-centre queues until an agent answers, the caller abandons, or the queue's own maxWaitTime
QueueAction parks the caller in one of the workspace's call-centre queues until an agent answers, the caller abandons, or the queue's own maxWaitTime expires. Actions placed AFTER a Queue run when the caller LEAVES it, however it ended — that is how an unanswered caller reaches voicemail, and why a Queue is not a terminal verb. It is also how queue-full overflow is handled: when the queue is at its configured maxDepth the PBX does not park the caller at all and simply continues with the next action. The queue is the PBX's own ACD. The switch owns the waiting, so there is NO hold ceiling: this verb used to be a <Redirect>-driven callback loop of ours, and every cycle of it spent part of the PBX's 50-actions-per-call budget, which capped a hold at roughly ten to twelve minutes. That limit is gone. The switch owns the matching too, so when an agent hangs up the next waiting caller reaches them in about 170ms, where the old loop took around 13 seconds to notice.
| Parameter | Type | JSON key | Required | Description |
|---|---|---|---|---|
Name | string | name | Yes | Name is the queue to join. Required, and deliberately BARE: there is no tenant attribute on this verb, because the PBX reads the workspace off the authenticated channel. If a callback could name the tenant, one workspace could park its caller in another workspace's queue. Constrained to [A-Za-z0-9._-] by validate — see ErrQueueName. |
WaitURL | string | waitUrl | No | WaitURL is the hold audio played while the caller waits. Prefer a STABLE url served with real cache headers, or set the hold audio on the queue itself and leave this empty. The switch caches hold audio by URL, so a freshly-signed URL per call is a new cache key on every join and the file is fetched BEFORE the caller is parked — measured at about 0.38s, against a park-to-ring that is otherwise about 170ms. A stable URL is fetched once and then costs nothing. Fallback order when the audio cannot be played: this URL, then the queue's own hold audio, then a tone. A waiting caller never hears silence. |
CallerID | string | callerId | No | CallerID is the number presented to the agent when the queue offers them the call. We want the CALLER's number there, so whoever answers knows who they are about to speak to and can ring back if the line drops. Implemented on the box (PBX letter, 2026-08-29). Without it the agent sees whatever happened to be on the inbound leg — the first live queue call showed an agent "Outbound Call / public", faithfully passed through. Safe because every agent in a queue is one of the workspace's own devices, so the caller's number never reaches a carrier. An external number as an agent WOULD put it on a carrier leg, which is the spoofing case our Dial guard exists to prevent — and the box now refuses the override on any queue that is not wholly internal, so the guard no longer depends on us remembering. We still avoid setting it where it cannot apply. |
AnnounceVoice | string | announceVoice | No | AnnounceVoice names the Google Cloud TTS voice the switch speaks the queue's position announcements in — any Google Cloud voice name. Empty leaves the box on its own default, en-GB-Standard-F. Google publishes no en-KE, en-ZA or en-NG voice, so a local English accent is not on the menu anywhere in the region and en-GB-Standard-F is the closest neutral default. The Swahili sw-KE Chirp3-HD voices are available and good — sw-KE-Chirp3-HD-Achernar, for one — but a position announcement spoken in Swahili would need Swahili numerals, and the switch does not speak those, so a Swahili announce voice is not something we do yet. Constrained to [A-Za-z0-9-] by validate, and refused rather than stripped — see ErrQueueAnnounceVoice. The value is spliced into a space-separated ESL scheduler command on the box, so anything carrying whitespace is not a malformed voice name, it is an extra command. |
res.json({
actions: [
{ queue: { name: "support", waitUrl: "https://cdn.example.com/audio/hold.mp3", announceVoice: "en-GB-Standard-F" } },
{ redirect: { url: "https://your-app.example.com/voice/queue-timed-out" } },
],
});{
"actions": [
{
"queue": {
"name": "support",
"waitUrl": "https://cdn.example.com/audio/hold.mp3",
"announceVoice": "en-GB-Standard-F"
}
},
{
"redirect": {
"url": "https://your-app.example.com/voice/queue-timed-out"
}
}
]
}<Queue waitUrl="https://cdn.example.com/audio/hold.mp3" announceVoice="en-GB-Standard-F">support</Queue>