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.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.
How ESL Works
FreeSWITCH listens on TCP port 8021 by default (configurable inevent_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.
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 ofKey: 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.
| Header | Purpose |
|---|---|
Content-Type | Identifies the message type (auth/request, command/reply, text/event-plain, etc.) |
Content-Length | Number of bytes in the body that follows the blank line |
Reply-Text | Result of a command/reply message; starts with +OK or -ERR |
Job-UUID | Returned by bgapi commands to correlate async responses |
status API call:
\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
host— FreeSWITCH hostname or IP addressport— ESL port (default"8021")password— ESL password (default"ClueCon")socket_fd— file descriptor of an accepted socket (outbound mode only)
Methods
| Method | Returns | Description |
|---|---|---|
connected() | int | Returns 1 if the connection is alive, 0 otherwise |
getInfo() | ESLevent | In outbound mode, returns the session info event received on connect |
send(cmd) | int | Send a raw command string; does not wait for a reply |
sendRecv(cmd) | ESLevent | Send a raw command and block until the reply event arrives |
api(cmd, arg) | ESLevent | Execute a synchronous FreeSWITCH API command; blocks until complete |
bgapi(cmd, arg, job_uuid) | ESLevent | Execute a background (async) API command; returns immediately |
events(etype, value) | int | Subscribe to events ("plain", "xml", or "json" format; "all" or space-separated event names) |
filter(header, value) | ESLevent | Add a header/value filter so only matching events are delivered |
recvEvent() | ESLevent | Block until the next event arrives |
recvEventTimed(ms) | ESLevent | Block up to ms milliseconds for the next event; returns NULL on timeout |
execute(app, arg, uuid) | ESLevent | Execute a dialplan application on the given call UUID |
executeAsync(app, arg, uuid) | ESLevent | Execute a dialplan application asynchronously |
setAsyncExecute(val) | int | Set the async-execute flag ("true" / "false") on this connection |
setEventLock(val) | int | Set the event-lock flag to serialize event delivery |
sendEvent(event) | ESLevent | Send an ESLevent object to FreeSWITCH |
sendMSG(event, uuid) | int | Send a sendmsg command targeting a specific call UUID |
socketDescriptor() | int | Return the raw socket file descriptor |
disconnect() | int | Gracefully close the ESL connection |
ESLevent API
Every reply, response, and event received over ESL is represented as anESLevent object. The class is defined in esl_oop.h alongside ESLconnection.
| Method | Returns | Description |
|---|---|---|
getHeader(name) | string | Retrieve the value of a named header |
getBody() | string | Retrieve the event body (e.g. raw API output) |
getType() | string | Return the event type string (e.g. "CHANNEL_ANSWER") |
serialize(format) | string | Serialize the event to "plain", "xml", or "json" text |
addHeader(name, value) | bool | Add a header to the event |
pushHeader(name, value) | bool | Append a header value (multi-value header support) |
unshiftHeader(name, value) | bool | Prepend a header value (multi-value header support) |
delHeader(name) | bool | Remove a header from the event |
addBody(value) | bool | Append text to the event body |
firstHeader() | string | Return the name of the first header (for iteration) |
nextHeader() | string | Return the name of the next header (for iteration) |
setPriority(priority) | bool | Set event priority |
Iterating headers
Authentication
When a client connects, FreeSWITCH immediately sends an authentication challenge: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:
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.