Transfer calls with SIP REFER
SIP REFER lets your app ask a SIP device or PBX to transfer a call to another destination. Start by transferring a call to another SIP address and handling the result, with a bridged transfer as the fallback, then track the transfer as it progresses.
Choose an approach
Each approach sends the REFER and receives its result in its own way, so pick the one that matches how your app controls the call and follow only its section. The sections don’t build on each other, and code from one doesn’t carry over to another.
- SWML: add
sip_referto your call document and branch on the result. The document waits for the transfer to finish. Optionally send events to a webhook. - WebSocket (Relay): send the REFER on an answered call from a Relay client and handle events in your code. No public URL is needed.
- REST: send the REFER by call ID from any process and receive results at a webhook.
Prepare for SIP REFER
Start with working call setup from Make and receive calls. You also need a SIP device or PBX that SignalWire can call, and a second SIP address the device can transfer the call to. Use a device and a target you can answer to test both stages of the transfer. The device must:
- Accept a REFER during an established call and reply
202 Accepted. A device that doesn’t support REFER, or that refuses transfers, replies with an error such as403,405, or501. - Place a call to the
Refer-ToURI. The device’s network and dial plan must allow calls to the target. - Report the new call’s progress in NOTIFY requests. Without them, SignalWire can’t tell whether the target answered: it waits about 32 seconds for the first NOTIFY, then reports success.
- Accept authentication credentials if it challenges the REFER. Supply
usernameandpasswordwith the transfer request when required.
Check your device or PBX documentation for how it handles an incoming REFER, sometimes listed as blind or unattended transfer. The SIP overview covers registering a softphone with SignalWire for testing, and SIP trunking covers connecting a PBX.
REFER is a SIP request, so the call must be a SIP call, such as one SignalWire places to a SIP
URI. For phone and browser call legs, Relay and REST reject the command, and SWML sets
sip_refer_result to error. Use a bridged transfer, such as SWML connect,
for those call legs.
Replace these values in the samples you run:
How SIP REFER works
SignalWire sends a REFER request on an answered SIP call, with the transfer target in the
Refer-To header. The SIP device or PBX accepts with 202 Accepted, places a new call to the
target, and reports its progress to SignalWire in NOTIFY requests. When the target answers,
your app ends SignalWire’s leg. The device and target continue their call directly.
This is a blind, or unattended, transfer: the device calls the destination without your app speaking to the recipient first.
SignalWire waits about 32 seconds for the device to accept the REFER, about 32 seconds for its first NOTIFY, and up to two minutes for the target to answer. Only one REFER can run on a call at a time. Your app must hang up SignalWire’s leg after a successful transfer.
When to use SIP REFER instead of a bridged transfer
Use SIP REFER when a SIP device or PBX can reach the destination directly and your app no longer needs to control the call. The device places the new call from its own network, and your app ends SignalWire’s leg after the transfer succeeds.
For a bridged transfer, such as SWML connect, SignalWire calls the target and
joins the two call legs. Both legs remain active and carry audio through SignalWire for the
rest of the conversation. This keeps your app in control of the call and requires the target
to be reachable from SignalWire.
Common uses include:
- Return a call to your PBX. A PBX sends a call to a SignalWire SIP address so an app can answer it, and the app then decides which extension, queue, or group should take the call. REFER lets the PBX connect the caller there directly.
- Reach a destination only the device can dial, such as an internal extension or a SIP URI on a private network.
- Remove SignalWire from the audio path after the transfer, so the rest of the conversation no longer uses two SignalWire call legs.
Use a bridged transfer instead when the call isn’t a SIP call, when you need to keep recording or controlling the call after the transfer, or when the device doesn’t support REFER.
SIP REFER results and response codes
Every approach reports the same final result: SWML sets it in sip_refer_result, and Relay and
webhooks carry it as the event’s state.
A success result doesn’t always mean the target answered. If your app needs to know, check the
target’s response code before it hangs up: a 2xx code means the target answered.
SWML reads the codes from variables, and Relay and webhooks from event fields:
Event fields are strings, and an event omits a code that is 0 or -1. The target’s response
appears only on the final event.
Transfer calls via SWML
sip_refer waits for the transfer to finish, then sets the result and response
code variables, plus sip_refer_to with the target URI. It answers the call first if it hasn’t
been answered. Use switch on sip_refer_result to choose the next action. When
the call isn’t a SIP call or a REFER is already in progress, sip_refer_result is error and
both response code variables are unset.
Transfer a SIP call via SWML
Transfer the call to the target, then branch on the result. On success, the document hangs
up SignalWire’s leg. On error, it uses connect to bridge the call to the same target. The
default branch plays a failure message and hangs up for other results.
The bridged fallback requires the target to be reachable from SignalWire.
The SDK programs place the call to your SIP device as in Place a call via SWML. Each branch is built with the SDK’s SWML builder. The YAML and JSON tabs contain the equivalent complete document.
Run the example and answer on your SIP device. You hear “Transferring your call,” then the device calls the target. Answer at the target to complete the transfer and end SignalWire’s leg. Test again with the target busy or unanswered to hear the failure message.
If the device challenges the REFER, add username and password to sip_refer.
Track REFER results via SWML
Add status_url to sip_refer to receive JSON webhooks as the transfer progresses. The document
still waits for the final result and branches on sip_refer_result.
Only the first REFER the device accepts on a call sends inProgress. If you try another target
on the same call, expect the final result only. See the webhooks guide for endpoint
setup and testing.
Transfer calls via WebSocket (Relay)
Send the REFER on an answered SIP call with refer() and a sip device whose to is the
target. The method returns as soon as SignalWire starts the REFER, so register a
calling.call.refer handler first and read the event’s state for the result. If the call isn’t
a SIP call or a REFER is already in progress, refer() raises an error instead of sending events.
Transfer a SIP call via WebSocket (Relay)
Dial your SIP device, then refer the call to the target. The handler hangs up on success,
bridges the call to the target with connect() on error, and plays a message before hanging
up on busy or noAnswer. If the device challenges the REFER, add username and password to
the device’s params.
Call setup follows Place a call via WebSocket (Relay), with a sip device
instead of a phone device.
Answer on your SIP device. The program prints inProgress with the device’s 202, then
success with the target’s 200 once the target answers, and hangs up SignalWire’s leg. To
transfer an incoming SIP call, answer it first, then send the REFER.
Track REFER results via WebSocket (Relay)
The calling.call.refer handler is how Relay tracks the transfer. Each event carries state
(inProgress, then the final result), the target URI, the device’s reply to the REFER, and the
target’s response from NOTIFY, the same values as the SWML webhook
fields. As in SWML, only the first REFER the device accepts on a
call sends inProgress. To send the same events to a webhook as well, pass a status URL to
refer().
Transfer calls via REST
Send calling.refer with an answered SIP call’s ID from any process, such as one
that didn’t place the call. The command returns immediately, and the result arrives at your
webhook.
Transfer a SIP call via REST
Send the command with a sip device whose to is the target, and status_url. Add username
and password to the device’s params if the device challenges the REFER. Use the
Server SDKs REST client’s calling.refer() to send the command:
To call the REST API directly, see Call commands.
Track REFER results via REST
Your webhook receives the calling.call.refer events described in
Track REFER results via SWML. Have the handler send the next
call command, such as calling.end on success, or calling.transfer to a document that uses
connect on error.