Initiate call from Lua


I’m using FreeSwitch as a client registered to an external PBX. I can make and receive calls, and it’s Subscribed to Presence notifications, so I can get Events triggered when an extension on the external PBX changes state (“on the phone”, “ringing”, “ready”, etc).

I’ve created an Event Hook in Lua which responds to Presence Notifications, and this is currently just sending Log entries so I can see when the state of external extensions has changed. It’s working nicely.

Now I want to initial a call in FreeSwitch when an extension changes from “on the phone” to “ready”. It’s not clear to me how, in Lua, I can initiate a call.

Lua API Reference | FreeSWITCH Documentation suggests to me that I need to create a “Session”,

I need to pass some data from the Event Hook to the Dialplan, so once I have a Session in progress I assume I use session:setVariable to do that: Lua API Reference | FreeSWITCH Documentation

I’ve looked up FreeSwitch Sessions and found Session | FreeSWITCH Documentation but I’m still not quite sure about things like “at what point does the call actually get placed to the person who needs to answer it?”


  1. Am I going in the right direction with this, thinking that I need to create a Session in Lua, which can then cause a call to be placed in the dialplan, or should I be going about this some completely other way?

  2. How does the timing of creating a Session, using setVariable, and actually placing the call (which uses some of the variable values) work together?

If anyone can point me at documented examples of how this should be done (I’ve looked, but been unable to find anything) that would be a great start.



Depends what are you doing exactly and where are you doing these hooks? You can hook into events in lua.conf.xml and never bother the session.


I have indeed created a hook in lua.conf.xml:

<hook event="NOTIFY_IN" script="Events.lua"/>

This calls my script Events.lua, which currently uses freeswitch.consoleLog to
show me that it’s got the right data and can parse it the way I need.

Now I need it to place a phone call to someone.

If you need detail of what I’m doing and why:

  • someone places a call which is for a number (“extension”) on the external
    PBX which happens to be busy at the time

  • the Lua script receives a Notify_in Event when the Presence Notification
    comes in from the external PBX saying that the extension is no longer busy

  • the script then needs to cause a call to be placed, not to the number which
    originally tried to place the call (so a simple “camp on” function won’t do
    what I want), but instead to a number which points at a queue, so the first
    agent in the queue able to take the call gets it and can deal with it.

What is the best way to get a Lua script to initiate a call? There is no
requirement for any audio; this simply needs to go to a standard SIP
telephone, with special Caller ID name and number, telling the person what
they need to do (hence the requirement for the Lua script to pass variables
into the dialplan before it makes the call).

I hope that explains in sufficient detail.



Did the additional detail I provided give enough context for someone to be
able to suggest whether I’m going about this the right way, and how I can get
Lua to initiate a call?

I simply find the documentation about freeswitch.Session, for example, rather
lacking in detail or examples, to show me how it should be used in practice.


You’ll just use the API object and originate a call… do you know all the details such as the endpoint you need to call, its URL?


Hi Brian

How can we pass the variable in argv[1] when we are sending the api request from postman to run the LUA bridge script.

Show me what you’re trying to do first so I can give you the right answer.

Basicall I trying to merege two call using bridge functionality. Calling First number after connected to first number calling to second number and once second number is connected trying to merge them using below lua script.

Now I need to pass value of argv[1] and argv[2] via postman using below api link


as of now it is working for hardcoded value as mentioned in the script but same we have to send dynamic number via api for outbound calling purpose.

Do you have any idea how to achieve the same ?

uuid = 123456789;
dialstr1 = argv[1] Need to pass this from postman in variable—>“sofia/gateway/audiocode/1298XXXXXXXXX”;
dialstr2 = argv[2] Need to pass this from postman in variable—>“sofia/gateway/audiocode/1298XXXXXXXXX”;
max_retriesl1 = 1;
max_retriesl2 = 1;
connected = false;
timeout = 45;
local sessionOneAnswered = false
freeswitch.consoleLog(“notice”, “*********** STARTING Call \n");
freeswitch.consoleLog(“notice”, "
DIALING “…dialstr1…” \n");
originate_base1 = “{ignore_early_media=true,originate_timeout=90,hangup_after_bridge=true,uuid=”…uuid…“,leg=1}”;
originate_str1 = originate_base1…dialstr1;
session1 = null;
session2 = null;
session = null;
retries = 0;
ostr = “”;
retries = retries + 1;
if (retries % 2) then
ostr = originate_str1;
freeswitch.consoleLog(“notice”, "
Dialing Leg1: " … ostr … " - Try: “…retries…” \n");
session1 = freeswitch.Session(ostr);
local hcause = session1:hangupCause();
freeswitch.consoleLog(“notice”, "
Leg1: " … hcause … " - Try: “…retries…” \n");
until not ((hcause == ‘NO_ROUTE_DESTINATION’ or hcause == ‘RECOVERY_ON_TIMER_EXPIRE’ or hcause == ‘INCOMPATIBLE_DESTINATION’ or hcause == ‘CALL_REJECTED’ or hcause == ‘NORMAL_TEMPORARY_FAILURE’) and (retries < max_retriesl1))
if (session1:ready()) then
– log to the console
freeswitch.consoleLog(“notice”, "
Leg1 (”…ostr…“) CONNECTED! ***********\n”);
session1:setVariable(“ringback”, “%(2000,4000,440,480)”);

for j = 1, 35 do
freeswitch.consoleLog(“info”, “+++++++++++++++++in loop ++++++++++” … j)

if session1:answered() then
freeswitch.consoleLog(“info”, “+++++++++++++++++inside if ++++++++++” … j)
sessionOneAnswered = true

    break ;

elseif (session1:hangupCause() == "USER_BUSY") then

   break ;	


if (sessionOneAnswered) then
session1:setVariable(“ringback”, “%(2000,4000,440,480)”);

session1:setVariable(“RECORD_STEREO”, “true”);
session1:execute(“record_session”, “C:/Users/Administrator/Downloads/recordings/external/”…dialstr1…“.mp3”);

– Create session2

originate_base2 = “{ignore_early_media=true,originate_timeout=90,hangup_after_bridge=true,uuid=”…uuid…“,leg=2}”;
originate_str2 = originate_base2…dialstr2;
ostr2 = originate_str2
freeswitch.consoleLog(“notice”, “*********** Dialing: " … ostr2 … " Try: “…retries…” ***********\n”);

    session2 = freeswitch.Session(ostr2, session1);

    local hcause = session2:hangupCause();

   freeswitch.consoleLog("notice", "*********** Leg2: " .. hcause .. " Try: " .. retries .. " ***********\n");

if (session2:ready()) then

    freeswitch.consoleLog("notice", "*********** Leg2 ("..ostr2..") CONNECTED! ***********\n");

    freeswitch.bridge(session1, session2);

    -- session2 if session1 is over

    if (session2:ready()) then 
     freeswitch.consoleLog("notice", "***********session2 disconnected*********")

-- hangup when done

if (session1:ready()) then
freeswitch.consoleLog(“notice”, “**session1 disconnected”)
session1:hangup(); end

Hi Brian
getting below issue, can you please help on this.
Freeswitch sending SIP/2.0 488 Not Acceptable Here
Via: SIP/2.0/WSS 0kpqr9eqgf8o.invalid;branch=z9hG4bK4154591;received=;rport=58943
Max-Forwards: 70
To: sip:12987021726666@x.x.x.x;tag=9tpHyKFamt2ap
Call-ID: dd1dgrkbk1g37cba4t75
User-Agent: Jio
Accept: application/sdp
Supported: timer, path, replaces
Allow-Events: talk, hold, conference, presence, as-feature-event, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer
Reason: Q.850;cause=88;text=“INCOMPATIBLE_DESTINATION”
Content-Length: 0
Remote-Party-ID: “12987021726666” sip:12987021726666@x.x.x.x.;party=calling;privacy=off;screen=no For Invite INVITE sip:12987021729774@ SIP/2.0
Via: SIP/2.0/WSS 0kpqr9eqgf8o.invalid;branch=z9hG4bK4154591
To: sip:12987021726666@x.x.x.x
Call-ID: dd1dgrkbk1g37cba4t75
Max-Forwards: 70
Contact: sip:5ceth6nh@0kpqr9eqgf8o.invalid;transport=ws;ob
Supported: outbound
User-Agent: SIP.js/0.21.1
Content-Type: application/sdp
Content-Length: 1736

o=- 8465964380331798740 2 IN IP4
t=0 0
a=group:BUNDLE 0
a=msid-semantic: WMS a495b80c-139a-4f0a-a736-bccdddd17f4b
m=audio 52245 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
c=IN IP4
a=rtcp:9 IN IP4
a=candidate:1852297919 1 udp 2122194687 52245 typ host generation 0 network-id 1
a=candidate:313672034 1 udp 2122262783 2402:8e00::3002:34d2:1f5f:cb5b:a31a 52246 typ host generation 0 network-id 2
a=candidate:279457831 1 tcp 1518214911 9 typ host tcptype active generation 0 network-id 1
a=candidate:1820173306 1 tcp 1518283007 2402:8e00::3002:34d2:1f5f:cb5b:a31a 9 typ host tcptype active generation 0 network-id 2
a=fingerprint:sha-256 03:E4:89:C9:3B:2D:0F:cc:A7:30:0E:0B:42:37:72:CA:DE:64:92:DB:7A:BC:0D:2E:2A:62:61:9F:FE:B2:54:6D
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 docs/native-code/rtp-hdrext/abs-send-time - src - Git at Google
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=msid:a495b80c-139a-4f0a-a736-bccdddd17f4b 98c882e6-ef06-497b-bd77-a0d00136dd8c
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
a=ssrc:3826604302 cname:z/VhkPyL3E6p2/Az
a=ssrc:3826604302 msid:a495b80c-139a-4f0a-a736-bccdddd17f4b 98c882e6-ef06-497b-bd77-a0d00136dd8c