Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/signalwire/freeswitch/llms.txt

Use this file to discover all available pages before exploring further.

The Event Socket Layer (ESL) is FreeSWITCH’s built-in TCP interface for external call control. It lets any application — written in Python, Lua, Ruby, Perl, Java, C#, or any language with socket support — connect to a running FreeSWITCH instance, issue API commands, subscribe to real-time call events, originate outbound calls, and manipulate active sessions. ESL is the foundation for building everything from simple call automation scripts to full-featured contact centre platforms.

How ESL Works

FreeSWITCH listens on TCP port 8021 by default (configurable in event_socket.conf.xml). The protocol is entirely text-based: a client opens a plain TCP connection, authenticates with a password challenge, then exchanges newline-delimited key/value messages with the server. ESL operates in two distinct modes:

Inbound Mode

Your application connects to FreeSWITCH on port 8021. Use this to send API commands, subscribe to events, and control calls from a central management process.

Outbound Mode

FreeSWITCH connects to your application when a call matches a dialplan extension. Use this to drive individual call legs with precise, session-level control.
The default authentication password is ClueCon. You must change this in any production deployment.
Always set a strong, unique password in event_socket.conf.xml before exposing FreeSWITCH on a non-loopback interface. The default ClueCon password is well-known and will be probed by automated scanners.

ESL Protocol Basics

All ESL messages share a common wire format: a series of Key: Value header lines followed by a blank line. If the message carries a body (for example, an API response or an event payload), the Content-Length header indicates how many bytes to read after the blank line.
Content-Type: auth/request

Content-Type: command/reply
Reply-Text: +OK accepted

Content-Type: text/event-plain
Content-Length: 422

Event-Name: CHANNEL_ANSWER
...
Key protocol headers:
HeaderPurpose
Content-TypeIdentifies the message type (auth/request, command/reply, text/event-plain, etc.)
Content-LengthNumber of bytes in the body that follows the blank line
Reply-TextResult of a command/reply message; starts with +OK or -ERR
Job-UUIDReturned by bgapi commands to correlate async responses
Example raw ESL session — authentication followed by a status API call:
# Server sends auth challenge immediately on connect:
Content-Type: auth/request

# Client authenticates:
auth ClueCon

# Server confirms:
Content-Type: command/reply
Reply-Text: +OK accepted

# Client runs a synchronous API command:
api status

# Server responds:
Content-Type: api/response
Content-Length: 150

UP 0 years, 0 days, 0 hours, 4 minutes, 32 seconds, 768 milliseconds, 0 microseconds
FreeSWITCH (Version 1.10.x) is ready
...
Messages are separated by a blank line (\n\n). Read until you encounter the blank line, then read exactly Content-Length bytes for the body.

ESLconnection API

ESLconnection is the primary class exposed by all ESL language bindings. It wraps the underlying TCP socket, handles authentication, and provides methods for every common ESL operation. The class is defined in libs/esl/src/include/esl_oop.h and generated for each language via SWIG.

Constructor

ESLconnection(host, port, password)
ESLconnection(host, port, user, password)  // with optional username
ESLconnection(socket_fd)                   // outbound mode: wrap an existing fd
Parameters:
  • host — FreeSWITCH hostname or IP address
  • port — ESL port (default "8021")
  • password — ESL password (default "ClueCon")
  • socket_fd — file descriptor of an accepted socket (outbound mode only)

Methods

MethodReturnsDescription
connected()intReturns 1 if the connection is alive, 0 otherwise
getInfo()ESLeventIn outbound mode, returns the session info event received on connect
send(cmd)intSend a raw command string; does not wait for a reply
sendRecv(cmd)ESLeventSend a raw command and block until the reply event arrives
api(cmd, arg)ESLeventExecute a synchronous FreeSWITCH API command; blocks until complete
bgapi(cmd, arg, job_uuid)ESLeventExecute a background (async) API command; returns immediately
events(etype, value)intSubscribe to events ("plain", "xml", or "json" format; "all" or space-separated event names)
filter(header, value)ESLeventAdd a header/value filter so only matching events are delivered
recvEvent()ESLeventBlock until the next event arrives
recvEventTimed(ms)ESLeventBlock up to ms milliseconds for the next event; returns NULL on timeout
execute(app, arg, uuid)ESLeventExecute a dialplan application on the given call UUID
executeAsync(app, arg, uuid)ESLeventExecute a dialplan application asynchronously
setAsyncExecute(val)intSet the async-execute flag ("true" / "false") on this connection
setEventLock(val)intSet the event-lock flag to serialize event delivery
sendEvent(event)ESLeventSend an ESLevent object to FreeSWITCH
sendMSG(event, uuid)intSend a sendmsg command targeting a specific call UUID
socketDescriptor()intReturn the raw socket file descriptor
disconnect()intGracefully close the ESL connection

ESLevent API

Every reply, response, and event received over ESL is represented as an ESLevent object. The class is defined in esl_oop.h alongside ESLconnection.
MethodReturnsDescription
getHeader(name)stringRetrieve the value of a named header
getBody()stringRetrieve the event body (e.g. raw API output)
getType()stringReturn the event type string (e.g. "CHANNEL_ANSWER")
serialize(format)stringSerialize the event to "plain", "xml", or "json" text
addHeader(name, value)boolAdd a header to the event
pushHeader(name, value)boolAppend a header value (multi-value header support)
unshiftHeader(name, value)boolPrepend a header value (multi-value header support)
delHeader(name)boolRemove a header from the event
addBody(value)boolAppend text to the event body
firstHeader()stringReturn the name of the first header (for iteration)
nextHeader()stringReturn the name of the next header (for iteration)
setPriority(priority)boolSet event priority

Iterating headers

h = event.firstHeader()
while h:
    print(f"{h}: {event.getHeader(h)}")
    h = event.nextHeader()

Authentication

When a client connects, FreeSWITCH immediately sends an authentication challenge:
Content-Type: auth/request
The client must respond with:
auth <password>\n\n
On success FreeSWITCH replies:
Content-Type: command/reply
Reply-Text: +OK accepted
On failure:
Content-Type: command/reply
Reply-Text: -ERR invalid
All ESL language bindings handle this handshake automatically inside the ESLconnection constructor — by the time the constructor returns, authentication has already completed (or failed, leaving connected() returning 0). The password is configured in event_socket.conf.xml:
<configuration name="event_socket.conf" description="Socket Client">
  <settings>
    <param name="nat-map"     value="false"/>
    <param name="listen-ip"   value="::"/>
    <param name="listen-port" value="8021"/>
    <param name="password"    value="ClueCon"/>
    <!--<param name="apply-inbound-acl" value="loopback.auto"/>-->
  </settings>
</configuration>
The apply-inbound-acl parameter restricts which IP addresses may connect. Uncomment it and set an ACL name (defined in acl.conf.xml) when you need network-level access control on top of password authentication.

Connection Modes

Inbound Mode

Your app dials in to FreeSWITCH. Best for global event subscriptions, system-wide API calls, and managing multiple concurrent calls from one process.

Outbound Mode

FreeSWITCH dials your app for each call. Best for per-call IVR logic, recording, and scenarios where each call needs isolated, sequential application control.
See Inbound Mode and Outbound Mode for full configuration and code examples, and Language Bindings for ready-to-run examples in Python, Lua, Perl, Ruby, Java, and C#.

Build docs developers (and LLMs) love