I am having a hard time trying to remove asterisk from the middle by doing either an attended or blind transfer, essentially a SIP Refer. I can get a 302 to work but its before the channel enters a stasis app and its done via the dialplan. Once the channel enters the stasis app I have tried to use both /continue and /redirect. With /continue its just hitting a different extension on the dial plan which works with Dial app but keeps asterisk in the middle. I have tried Transfer and BlindTransfer apps but it fails, doesnt even send a sip request unless its not logged.
The channel is not bridged, just a normal channel that enters a stasis app where we play prompts and receive dtmf. Later in the call flow we want to do an attended or blind transfer to remove asterisk from the middle.
Asterisk 22
Pjsip
; extensions_ari.conf
exten = 3500,1,Answer()
same = n,Set(JITTERBUFFER(adaptive)=default)
same = n,Stasis(myStasisApp)
same = n,Hangup()
exten = 3501,1,BlindTransfer(PJSIP/sip:user@ipAddress:port)
same = n,Hangup()
exten = 3501,1,Transfer(PJSIP/transfer-test)
same = n,Hangup()
; pjsip.conf
[transfer-test]
type=endpoint
context=myCustomContext
disallow=all
allow=ulaw
aors=transfer-test-aor
allow_transfer=yes
; tested with or without direct media
[transfer-test-aor]
type=aor
contact=sip:user@ipAddress:port
Extension 3501 in extensions_ari.conf is just showing a couple of ways I tested with no luck.
I can post logs for any desired scenario. What is the proper way to do a SIP refer (some transfer/redirect to remove asterisk from the middle) once a channel enters a stasis app?
jcolp
March 4, 2026, 1:43pm
2
There is no ability to trigger an attended transfer. For a SIP REFER it would be using Transfer() or /redirect as you’ve stated. I would suggest providing actual console output of an attempt including SIP trace (pjsip set logger on) and the ARI interaction.
– Ex. calling dialplan extension directly to show it works as a 302 and at least routable.
[2026-03-04 09:10:36] VERBOSE[967] res_pjsip_logger.c: <— Transmitting SIP response (436 bytes) to UDP:myInternalSoftphoneIp:5060 —>
SIP/2.0 302 Moved Temporarily
Via: SIP/2.0/UDP myInternalSoftphoneIp:5060;rport=5060;received=myInternalSoftphoneIp;branch=z9hG4bK78722080
Call-ID: 1772226310-22080@myInternalSoftphoneIp
From: “3369586321” sip:3369586321@myInternalSoftphoneIp ;tag=4767
To: sip:3501@myInternalSoftphoneIp ;tag=59239d4c-c334-4dbd-8255-1803463ace42
CSeq: 797 INVITE
Server: Asterisk PBX GIT-22-22.0.0-pre1-367-g39a508cc71
Contact: sip:user@ipAddress:5060
Content-Length: 0
[2026-03-04 09:10:36] VERBOSE[972] res_pjsip_logger.c: <— Received SIP request (378 bytes) from UDP:myInternalSoftphoneIp:5060 —>
ACK sip:3501@asteriskInternalIp SIP/2.0
Via: SIP/2.0/UDP myInternalSoftphoneIp:5060;rport;branch=z9hG4bK78722080
To: sip:3501@asteriskInternalIp ;tag=59239d4c-c334-4dbd-8255-1803463ace42
From: “3369586321” sip:3369586321@asteriskInternalIp ;tag=4767
Call-ID: 1772226310-220804@myInternalSoftphoneIp
CSeq: 797 ACK
Max-Forwards: 20
User-Agent: NCH Software Express Talk 4.35
Content-Length: 0
– Ari /continue to dialplan extension 3501 which immediately calls the Transfer app
[2026-03-04 09:21:22] DEBUG[323705] res_http_websocket.c: Writing websocket string of length 827
[2026-03-04 09:21:22] DEBUG[323705] res_http_websocket.c: Writing websocket text frame, length 827
[2026-03-04 09:21:22] DEBUG[323705] ari/ari_websockets.c: 10.249.50.52:60945: Dispatched ‘ChannelCallerId’ message from Stasis app ‘myStasisApp’
[2026-03-04 09:21:22] DEBUG[323754] http.c: HTTP Request URI is /ari/channels/1772634050.54637/continue?context=myTestContext&extension=3501
[2026-03-04 09:21:22] DEBUG[323754] http.c: match request [ari/channels/1772634050.54637/continue] with handler [httpstatus] len 10
[2026-03-04 09:21:22] DEBUG[323754] http.c: match request [ari/channels/1772634050.54637/continue] with handler [ari] len 3
[2026-03-04 09:21:22] DEBUG[323754] http.c: Match made with [ari]
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: 10.249.50.52:65244: Request: POST channels/1772634050.54637/continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: No post_vars
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking body for vars
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: app_name: (null)
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Request: POST channels/1772634050.54637/continue, path:channels/1772634050.54637/continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Finding handler for path segment channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment events
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari events: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking events
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment asterisk
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari asterisk: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking asterisk
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment applications
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari applications: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking applications
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment endpoints
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari endpoints: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking endpoints
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment sounds
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari sounds: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking sounds
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment recordings
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari recordings: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking recordings
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment deviceStates
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari deviceStates: Didn’t match channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking deviceStates
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking ari channels: Explicit match with channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking channels
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Finding handler for path segment 1772634050.54637
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment create
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking channels create: Didn’t match 1772634050.54637
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking create
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment channelId
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking channels channelId: Matched wildcard.
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking channelId
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment externalMedia
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking channels externalMedia: Didn’t match 1772634050.54637
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking externalMedia
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: No explicit handler found for 1772634050.54637. Using wildcard channelId.
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking 1772634050.54637
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Finding handler for path segment continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking handler path segment continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Checking channelId continue: Explicit match with continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done checking continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Running callback: channels/1772634050.54637/continue
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Response: 204 : No Content
[2026-03-04 09:21:22] DEBUG[323754] http.c: HTTP keeping session open. status_code:204
[2026-03-04 09:21:22] DEBUG[323754] res_ari.c: Done. response: 204 : No Content
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] stasis/app.c: channel ‘1772634050.54637’: is 0 interested in myStasisApp
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] stasis/app.c: channel ‘1772634050.54637’ unsubscribed from myStasisApp
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] taskprocessor.c: Taskprocessor ‘stasis/m:ari:application/myStasisApp-00001fd4’: Task pushed from stasis.c:1454 (dispatch_message)
[2026-03-04 09:21:22] DEBUG[323705] ari/ari_websockets.c: 10.249.50.52:60945: Dispatching message from Stasis app ‘myStasisApp’
[2026-03-04 09:21:22] VERBOSE[323705] ari/ari_websockets.c: <— Sending ARI event to myStasisAppIpAddress:60945 —>
{
“type”: “StasisEnd”,
“timestamp”: “2026-03-04T09:21:22.622-0500”,
“channel”: {
“id”: “1772634050.54637”,
“name”: “PJSIP/anonymous-0000d56d”,
“state”: “Up”,
“protocol_id”: “1772226313-22080@internalIpAddress”,
“caller”: {
“name”: “Charles”,
“number”: “3369586321”
},
“connected”: {
“name”: “”,
“number”: “”
},
“accountcode”: “”,
“dialplan”: {
“context”: “myTestContext”,
“exten”: “3500”,
“priority”: 3,
“app_name”: “Stasis”,
“app_data”: “myStasisApp”
},
“creationtime”: “2026-03-04T09:20:50.700-0500”,
“language”: “en”
},
“asterisk_id”: “00:0c:29:3f:a6:72”,
“application”: “myStasisApp”
}
[2026-03-04 09:21:22] DEBUG[323705] res_http_websocket.c: Writing websocket string of length 726
[2026-03-04 09:21:22] DEBUG[323705] res_http_websocket.c: Writing websocket text frame, length 726
[2026-03-04 09:21:22] DEBUG[323705] ari/ari_websockets.c: myStasisAppIpAddress:60945: Dispatched ‘StasisEnd’ message from Stasis app ‘myStasisApp’
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] pbx.c: Launching ‘Transfer’
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] taskprocessor.c: Taskprocessor ‘pjsip/distributor-0000003b’: Task pushed from chan_pjsip.c:2187 (chan_pjsip_transfer)
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] app_transfer.c: ast_transfer channel PJSIP/anonymous-0000d56d TRANSFERSTATUS=FAILURE, TRANSFERSTATUSPROTOCOL=1
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] pbx.c: Launching ‘Wait’
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] channel.c: Channel PJSIP/anonymous-0000d56d setting write format path: slin → ulaw
[2026-03-04 09:21:22] DEBUG[323746][C-0000b51c] res_musiconhold.c: PJSIP/anonymous-0000d56d Opened file 0 ‘/var/lib/asterisk/moh/manolo_camp-morning_coffee’
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] channel.c: Soft-Hanging (0x10) up channel ‘PJSIP/anonymous-0000d56d’
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] channel.c: Channel 0x7ff380100b70 ‘PJSIP/anonymous-0000d56d’ hanging up. Refs: 2
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] abstract_jb.c: JITTERBUFFER hook destroyed
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] channel.c: Channel PJSIP/anonymous-0000d56d setting write format path: ulaw → ulaw
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] chan_pjsip.c: PJSIP/anonymous-0000d56d
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] chan_pjsip.c: AST hangup cause 0 (no match found in PJSIP)
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] taskprocessor.c: Taskprocessor ‘pjsip/distributor-0000003b’: Task pushed from chan_pjsip.c:2603 (chan_pjsip_hangup)
[2026-03-04 09:21:23] DEBUG[323746][C-0000b51c] chan_pjsip.c: PJSIP/anonymous-0000d56d: Cause: 0 Tech Cause: 0
[2026-03-04 09:21:23] DEBUG[967] chan_pjsip.c: PJSIP/anonymous-0000d56d
[2026-03-04 09:21:23] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56d Response 0
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (0x7ff38008add0) DTLS srtp - stopped timeout timer’
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (0x7ff38008add0) DTLS srtp - stopped timeout timer’
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (1772634050.54637) RTP Stop
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (0x7ff38008add0) DTLS stop
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (0x7ff38008add0) DTLS srtp - stopped timeout timer’
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (0x7ff38008add0) DTLS srtp - stopped timeout timer’
[2026-03-04 09:21:23] DEBUG[967] res_rtp_asterisk.c: (0x7ff38008add0) ICE RTP transport deallocating
[2026-03-04 09:21:23] DEBUG[967] rtp_engine.c: Destroyed RTP instance ‘0x7ff38008add0’
[2026-03-04 09:21:23] DEBUG[967] stream.c: Topology: 0x7ff3800b49f8: <0:audio-0:audio:sendrecv (ulaw)>
[2026-03-04 09:21:23] DEBUG[967] stream.c: Destroyed: 0x7ff3800b49f8
[2026-03-04 09:21:23] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56d: Method is BYE
[2026-03-04 09:21:23] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56d
exten = 3501,1,Transfer(PJSIP/transfer-test)
same = n,Wait(1) ; had a longer wait to check channel manually, should be prompt then hangup
jcolp
March 4, 2026, 2:41pm
6
I’d also do a test by calling Answer(), Wait(1), Transfer() in the dialplan and eliminate ARI as a factor.
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c: The current inv state is CONFIRMED
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56e: Received request
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56e: Method is ACK
[2026-03-04 09:46:57] DEBUG[967] chan_pjsip.c: PJSIP/anonymous-0000d56e
[2026-03-04 09:46:57] DEBUG[967] chan_pjsip.c: PJSIP/anonymous-0000d56e
[2026-03-04 09:46:57] DEBUG[967] chan_pjsip.c: PJSIP/anonymous-0000d56e
[2026-03-04 09:46:57] DEBUG[967] chan_pjsip.c: PJSIP/anonymous-0000d56e
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56e
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c:
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56e Request: ACK
[2026-03-04 09:46:57] DEBUG[967] res_pjsip_session.c: PJSIP/anonymous-0000d56e Handled request ACK ? yes
[2026-03-04 09:46:58] DEBUG[323829][C-0000b51d] channel.c: Didn’t receive a media frame from PJSIP/anonymous-0000d56e within 500 ms of answering. Continuing anyway
[2026-03-04 09:46:58] DEBUG[323829][C-0000b51d] pbx.c: Launching ‘Wait’
[2026-03-04 09:46:59] DEBUG[323829][C-0000b51d] pbx.c: Launching ‘Transfer’
[2026-03-04 09:46:59] DEBUG[323829][C-0000b51d] taskprocessor.c: Taskprocessor ‘pjsip/distributor-0000001d’: Task pushed from chan_pjsip.c:2187 (chan_pjsip_transfer)
[2026-03-04 09:46:59] DEBUG[323829][C-0000b51d] app_transfer.c: ast_transfer channel PJSIP/anonymous-0000d56e TRANSFERSTATUS=FAILURE, TRANSFERSTATUSPROTOCOL=1
[2026-03-04 09:46:59] DEBUG[323829][C-0000b51d] pbx.c: Launching ‘Wait’
[2026-03-04 09:47:00] DEBUG[323829][C-0000b51d] channel.c: Soft-Hanging (0x10) up channel ‘PJSIP/anonymous-0000d56e’
[2026-03-04 09:47:00] DEBUG[323829][C-0000b51d] channel.c: Channel 0x7ff380100b70 ‘PJSIP/anonymous-0000d56e’ hanging up. Refs: 2
[2026-03-04 09:47:00] DEBUG[323829][C-0000b51d] chan_pjsip.c: PJSIP/anonymous-0000d56e
[2026-03-04 09:47:00] DEBUG[323829][C-0000b51d] chan_pjsip.c: AST hangup cause 0 (no match found in PJSIP)
The log above was from calling the extension directly. Fails when adding the Answer and it has to do an actual Sip refer instead of 302. Invite was just fine, omitted in the logs.
exten = 3501,1,Answer()
same = n,Wait(1)
same = n,Transfer(PJSIP/transfer-test)
same = n,Wait(1) ; todo fix when transfer fails
I added the wrong module and the transfer app was silently failing.
res_pjsip_xfer.so vs res_pjsip_refer.so
Still need to do more testing but the extension is now working directly after an answer.
The destination needs to make sense to the remote system. I don’t think you have the option of using a PJSIP endpoint name. The documentation is bad, as it doesn’t adequately define “destination”, but you need a full SIP URI that is meaningful to the upstream system.
There is a request from Asterisk to Twilio and the response from Twilio to Asterisk. It is the latter that has the 5060. Addition: The REFER is being sent the URI specified in the Contact header provided by Twilio, which is correct, from the...
I have confirmed in asterisk 22 at least that a PJSIP endpoint name does work as long as its using a valid sip uri. Tested via ARI /redirect and also in the dial plan transfer app. I agree the documentation is lacking, hopefully this post helps someone in the future.