Queue calls
A call queue holds callers until someone is free to talk to them. Callers hear hold music while
they wait, and each time an agent becomes available, SignalWire connects the agent to the caller
who has waited longest. This guide builds a dispatch line for Bayview Taxi: callers wait in a
dispatch queue, and the dispatcher, Ada, takes them one at a time.
Choose an approach
Follow the section for your app’s approach. Each is a complete way to build the queue, and the sections don’t build on each other:
- SWML: a document puts the caller in the queue with
enter_queue, and a document on the agent’s call takes the next caller withconnect. SignalWire plays the hold music and enforces the wait limit. - WebSocket (Relay): your code puts an answered call in the queue and connects an agent’s call to it, and handles queue events as they happen. Your code plays the hold music and decides when a caller has waited too long. No public URL is needed.
Both approaches use the same queues, which you can create, inspect, and delete over REST whichever one you choose.
Prepare for call queues
Start with working call setup from Make and receive calls. To test a queue you need two phones: one to call in and wait as the caller, and one to answer as the agent.
A trial project only places calls to and receives calls from numbers you’ve purchased or verified. Prepare for your first call shows how to verify the phones you’ll test with.
Replace these values in the samples you run:
How call queues work
A queue is a named waiting line in your project. Two calls take part in every connection:
- The caller’s call enters the queue. SignalWire records the caller’s position. With SWML, SignalWire also plays hold audio while the caller waits; with Relay, your code plays it. A caller can wait in only one queue at a time.
- The agent’s call connects to the queue. This is a separate call: an agent dialing in, or a call you place to the agent. When it connects to the queue, SignalWire takes the caller who has waited longest and bridges the two calls.
- The bridge ends. When either side hangs up, the other side hangs up too, unless you gave it
SWML to run next with
execute_after_queue.
A caller can also leave without reaching an agent: they hang up, their wait limit runs out, or your code removes them.
Create a queue
You don’t have to create a queue first. When a call enters or connects to a queue name your project hasn’t used, SignalWire creates that queue. Names are case-sensitive, so a misspelled name creates a separate, empty queue.
Create a queue ahead of time when you want to set it up before any call arrives, or to look up its
ID for the REST examples in this guide. The Server SDKs create one with a name
that’s unique among your project’s queues:
To call the REST API directly, use Create queue:
The response’s id is the queue’s ID, and friendly_name is the name that calls use to reach it.
A request with a name that’s already in use fails with a validation error.
Run a call queue via SWML
enter_queue places the caller in a queue, and connect
with to: "queue:<name>" connects the agent’s call to the caller at the front.
Put a caller in a queue via SWML
Callers to your number hear a greeting, then wait in the dispatch queue for up to two minutes.
wait_time defaults to 180 seconds. SignalWire plays hold music until an agent connects; set
wait_url to an audio file to play your own.
The server below answers calls the way Answer a call via SWML does. Run it in place of that server, with the same public URL and SWML Script.
From the phone you’re using as the caller, call your SignalWire number. You hear the greeting, then hold music. Stay on the line for the next section, or wait two minutes to hear the busy message.
If you hear the busy message right after the greeting, the caller couldn’t enter the queue. When
you set wait_url, check that it points at a public audio file in WAV, MP3, AIFF, GSM, or μ-law
format: a file that can’t be played ends the wait.
Connect an agent to a waiting caller via SWML
Call the agent with a document that connects to the queue. When Ada answers, she hears a short announcement, then the caller who has waited longest. The call is placed as in Place a call via SWML.
With the caller phone still on hold, run the program and answer the agent phone. After the announcement, the hold music stops on the caller phone and the two phones can talk. Hang up either phone to end both calls.
If the agent hears “No callers are waiting.”, the queue was empty: connect doesn’t wait for a
caller to arrive. It sets connect_result to failed and the document continues. Check that the
caller is still on hold and that both documents use the same queue name, including case.
A queue: connect takes exactly one destination and doesn’t accept call_state_url or
call_state_events; track the queue with status_url on enter_queue instead. To run more SWML
on either call after the bridge ends, such as a short survey for the caller, set
execute_after_queue on enter_queue or on connect to a URL or an inline SWML document.
Take a caller out of a queue via SWML
SWML has no instruction that removes a caller from a queue. A waiting caller leaves the queue in one of three ways:
In the caller’s document from
Put a caller in a queue via SWML, the busy message plays for
any caller who leaves without reaching an agent. To give a different message per reason, put a
switch on queue_result after enter_queue.
To remove a caller before their wait runs out, end their call with the calling.end
call command, from any process. Get the caller’s call ID from a
queue event. The Server SDKs send the command with
end:
To call the REST API directly, send calling.end to Call commands:
The caller’s queue reports leave, and their call ends.
Track a queue via SWML
Add status_url to the enter_queue instruction in
Put a caller in a queue via SWML to receive a JSON webhook
each time the caller enters or leaves the queue. The webhooks guide covers endpoint
setup and local testing.
Each webhook has event_type: calling.call.queue and reports what happened in params.status:
A caller receives either dequeue or leave, never both. SignalWire doesn’t send updates while
the caller waits, so to watch positions change, read the
member list.
The enter_queue reference has a complete payload for each event. After
enter_queue, the caller’s document can also read entry_position and entry_size, the
caller’s position and the queue’s size when they entered, and wait_time, how many seconds a
caller who left without reaching an agent waited.
Run a call queue via WebSocket (Relay)
With Relay, your code places an answered call in a queue, then connects an agent’s call to the
queue with a queue device. Your server code must play the hold music and decide when the
caller has waited too long: in Relay, SignalWire plays no hold audio and doesn’t apply a wait
limit.
Put a caller in a queue via WebSocket (Relay)
This handler answers each call, plays a greeting, places the caller in the dispatch queue, and
loops hold music. It waits for the caller to leave the queue: a dequeue event means an agent took
them, and leave means they hung up. If neither happens within two minutes, the handler removes
the caller from the queue, plays a busy message, and hangs up.
The handler receives calls the way Answer a call via WebSocket (Relay) does. Run it in place of that handler, with the same topic and Relay Application.
From the phone you’re using as the caller, call your SignalWire number. You hear the greeting,
then your hold music, and the handler logs Queue: enqueue, position 1. Stay on the line for the next section.
If you hear silence instead of music, check that <YOUR_HOLD_MUSIC_URL> is a public audio file.
If no Queue: line appears, check that the handler registers its calling.call.queue listener
before the call enters the queue.
Connect an agent to a waiting caller via WebSocket (Relay)
Dial the agent, then connect the agent’s call with a queue device that names the queue. SignalWire takes
the caller who has waited longest and bridges the two calls. Watch calling.call.connect events on
the agent’s call to learn the outcome. The call is placed as in
Place a call via WebSocket (Relay).
With the caller phone still on hold, run the program and answer the agent phone. After the
announcement, the program logs Connect: connecting, then Connect: connected. The caller’s
handler logs Queue: dequeue, stops the hold music, and the two phones can talk. Hang up either phone to end both calls.
If the agent hears “No callers are waiting.” and the program logs Connect: failed, the queue was empty:
connecting doesn’t wait for a caller to arrive. Check that the caller is still on hold and that
both programs use the same queue name, including case.
Take a caller out of a queue via WebSocket (Relay)
Leaving the queue removes the caller and sends a leave event. The call stays up, so your code
decides what the caller hears next. In
Put a caller in a queue via WebSocket (Relay), the
handler leaves the queue when the caller’s two minutes run out, then plays the busy message. Leave
the queue the same way to offer a callback, send the caller to voicemail, or move them to another
queue.
A caller who hangs up leaves the queue on their own, and also sends a leave event. To remove a
caller from a process that doesn’t hold their call, end the call with the REST calling.end
command, as in Take a caller out of a queue via SWML.
Track a queue via WebSocket (Relay)
Register a calling.call.queue handler on the caller’s call before the call enters the queue, as
the caller’s handler does. The event carries the same fields as the
SWML webhooks: its status is enqueue, dequeue, or leave, and it
reports the queue’s ID and name, the caller’s position, and the queue’s size. To receive the same
events at a webhook instead, pass a status URL when the call enters the queue. The
Relay client guide covers event listeners in depth.
Monitor and manage queues via REST
The REST API reads and changes the same queues that SWML and Relay calls use. Calls reach a queue by name, and the REST API addresses it by ID. Use it to build a wallboard, decide which caller to handle next, or rename and clean up queues. The Server SDKs cover each operation:
Get a queue’s size and wait time via REST
This program lists your project’s queues with their IDs, how many callers each holds, and how long those callers have waited on average. Use it to find the ID of a queue that a call created by name:
To read one queue whose ID you know, use get or Get queue:
friendly_name is the name that calls use to reach the queue, and id is what every REST request
about it uses. current_size counts the callers waiting now, and average_wait_time is how long,
in seconds, those callers have waited on average: 0 when the queue is empty.
List queues returns your newest queues first, 50 to a page. Follow links.next in the response for
the next page, as Paging describes.
List the callers waiting in a queue via REST
This program prints every caller waiting in a queue, next caller first, with their position and
how long they’ve waited. The list returns the most recent callers first, 50 to a page, so the
program follows links.next through every page, as Paging describes, then sorts by
position:
A caller at position 1 has waited longest and is the next caller an agent’s call connects to.
wait_time is how long the caller has waited, in seconds.
A member’s call_id identifies them in this API only: it isn’t the call ID that queue events
report or that calling.end takes. To check one member again later, pass the call_id from the
list to Get queue member:
Update or delete a queue via REST
Update a queue to rename it:
A new name must be unique among your project’s queues. Renaming doesn’t change the documents and programs that use the old name: the next call that enters or connects to the old name creates a new queue with it.
To delete a queue, replace the last two lines of that program with the line below, or use
Delete queue. The queue must be empty: a queue with callers waiting returns
400 Bad Request and stays in place.