> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bananaflow.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Asterisk ARI Integration

> Connect Bananaflow AI to your Asterisk PBX using the Asterisk REST Interface (ARI)

## Overview

Asterisk ARI (Asterisk REST Interface) allows you to connect Bananaflow AI voice agents to your existing Asterisk PBX. ARI provides a WebSocket-based event model for controlling calls via Stasis applications, giving Bananaflow full control over call flow and audio streaming.

This guide focuses on the Bananaflow-specific configuration. For general Asterisk installation and administration, refer to the [official Asterisk documentation](https://docs.asterisk.org/).

## Prerequisites

Before setting up the ARI integration, ensure you have:

* A running Asterisk instance with `chan_websocket` and `res_websocket_client` modules available. Known-working setups: (a) Asterisk 22+, (b) Asterisk 20 LTS with these modules included
* ARI module enabled in Asterisk
* `chan_websocket` (WebSocket channel driver) and `res_websocket_client` (loads `websocket_client.conf`) enabled in your Asterisk build. Verify with `asterisk -rx "module show like chan_websocket"` and `asterisk -rx "module show like res_websocket_client"` – both should report **Running**.
* Network connectivity between Bananaflow and your Asterisk server

<Note>
  If you compiled Asterisk from source, ensure both `chan_websocket` and `res_websocket_client` are included during the build. These modules are required for external media streaming between Asterisk and Bananaflow. Refer to the [Asterisk build system documentation](https://docs.asterisk.org/) for details on enabling modules.
</Note>

## How setup fits together

Setup crosses between the two systems, so the order matters:

| | Where | What |
| - | - | - |
| **1** | Asterisk | Create the ARI user, enable the HTTP server, and add the external-media WebSocket client – the values Bananaflow asks for |
| **2** | Bananaflow | Enter those values and save. Bananaflow generates a **Stasis App Name** unique to this configuration |
| **3** | Asterisk | Put that generated name in your dialplan as `Stasis(<name>)` and reload |
| **4** | Bananaflow | Register the extensions that should reach an agent, then place a test call |

The dialplan comes last because the Stasis application name does not exist until the configuration is saved. Everything else can be set up in advance.

## Part 1: Asterisk connection settings

These are minimal examples focused on the Bananaflow integration -- refer to the [Asterisk documentation](https://docs.asterisk.org/) for full configuration details.

### Enable ARI (`ari.conf`)

Create an ARI user that Bananaflow will use to authenticate:

```ini theme={null}
[general]
enabled = yes

[bananaflow]
type = user
read_only = no
password = your_secure_password
```

<Note>
  The username (section name, e.g., `bananaflow`) and password here are the **ARI Username** and **App Password** you enter in Bananaflow. This name authenticates to Asterisk – it is *not* the Stasis application name, which Bananaflow generates for you in [Part 2](#part-2-create-the-configuration-in-bananaflow).
</Note>

### Enable the HTTP Server (`http.conf`)

ARI requires the Asterisk HTTP server to be enabled:

```ini theme={null}
[general]
enabled = yes
bindaddr = 0.0.0.0
bindport = 8088
```

### Configure External Media Streaming (`websocket_client.conf`)

Bananaflow uses Asterisk's external media streaming to send and receive audio over WebSocket. Configure a WebSocket client connection that points to Bananaflow:

```ini theme={null}
[bananaflow]
type = websocket_client
uri = wss://app.bananaflow.ai/api/v1/telephony/ws/ari
protocols = media
tls_enabled = yes
ca_list_file = /etc/ssl/certs/ca-certificates.crt
```

<Note>
  `tls_enabled = yes` is required even though the URI scheme is `wss://` – without it Asterisk will not negotiate TLS and the connection will fail. The ARI credentials (**ARI Username** and **App Password**) must match what you configure in the Bananaflow dashboard under Telephony Settings.
</Note>

<Note>
  The section name (e.g., `bananaflow`) is the **WebSocket Client Name** you'll enter in the Bananaflow telephony configuration. This name tells Asterisk which WebSocket connection to use for external media streaming during calls.
</Note>

<Note>
  Configure the `uri` as a base URL only, without a query string. During each call, Bananaflow asks Asterisk to create an `externalMedia` channel and Asterisk appends `workflow_id`, `organization_id`, and `workflow_run_id` through the `v()` transport data for that call. Opening `/api/v1/telephony/ws/ari` directly in a browser or with `wscat` can return HTTP 403 because those routing parameters are missing; that is expected and does not indicate a `websocket_client.conf` misconfiguration.
</Note>

<Note>
  Bananaflow's external media channel uses **G.711 μ-law (`ulaw`)**. Make sure any PJSIP endpoint or SIP trunk that places or receives calls through Bananaflow allows `ulaw` (e.g. `allow=ulaw` in the endpoint config).
</Note>

Refer to the [Asterisk WebSocket documentation](https://docs.asterisk.org/) for additional `websocket_client.conf` options and TLS configuration.

### Apply the configuration changes

Reload the affected Asterisk modules from the Asterisk CLI (`asterisk -rvvv`):

```bash theme={null}
module reload res_ari.so                   # picks up ari.conf changes
module reload res_websocket_client.so      # picks up websocket_client.conf changes
```

Changes to `http.conf` require a full Asterisk reload (`core reload`) or a service restart. `core reload` also covers both commands above if you would rather reload everything at once.

## Part 2: Create the configuration in Bananaflow

### Step 1: Navigate to Telephony Settings

1. Navigate to **/telephony-configurations** and click **Add configuration**
2. Select **Asterisk ARI** as your provider

### Step 2: Enter Your ARI Credentials

Configure the following fields:

| Field | Description | Example |
| - | - | - |
| **ARI Endpoint URL** | HTTP base URL of your Asterisk ARI server | `http://asterisk.example.com:8088` |
| **ARI Username** | The ARI username configured in `ari.conf` | `bananaflow` |
| **App Password** | The ARI password configured in `ari.conf` | `your_secure_password` |
| **WebSocket Client Name** | The connection name from `websocket_client.conf` | `bananaflow` |
| **From Extensions** | Optional SIP extensions or trunk numbers for outbound calls | `PJSIP/6001` or `6001` |
| **Dial String Template** | How a dialed number reaches your trunk. See [Outbound Calling](#outbound-calling) | `PJSIP/{number}@my-trunk` |

**Stasis App Name** is not something you enter – Bananaflow generates it when you save and displays it on the configuration for you to copy.

### Step 3: Save and copy the Stasis App Name

Click **Save Configuration**. Bananaflow assigns a **Stasis App Name** to this configuration – something like `bananaflow_a1b2c3d4e5f6` – and shows it on the configuration page. Copy it; you need it for [Part 3](#part-3-route-calls-into-the-stasis-application).

<Note>
  The Stasis App Name is generated, not chosen. Asterisk gives a Stasis application to whichever ARI connection registered for it most recently and stops delivering events to the previous one, with no error on either side. If two configurations named the same application on one Asterisk, one would silently stop receiving calls while the other received calls that were not its own. Generating the name is what prevents that.
</Note>

## Part 3: Route calls into the Stasis application

### Configure the Stasis Dialplan (`extensions.conf`)

Route incoming calls into the Stasis application Bananaflow generated for your configuration:

```ini theme={null}
[from-external]
exten => _X.,1,NoOp(Incoming call to ${EXTEN})
 same => n,Stasis(bananaflow_a1b2c3d4e5f6)
 same => n,Hangup()
```

Replace `bananaflow_a1b2c3d4e5f6` with the **Stasis App Name** from your configuration, then reload the dialplan:

```bash theme={null}
dialplan reload
```

<Warning>
  Until the dialplan names the generated application, calls reach Asterisk but never arrive at Bananaflow. This is the most common reason a correctly configured ARI integration receives no calls.
</Warning>

## Part 4: Add extensions and test

1. Add each SIP extension that should be reachable as a **phone number** (e.g. `8000`). For inbound, you'll assign a workflow to each extension separately – see [Inbound Calling](#inbound-calling) below.
2. Create a test workflow and initiate a test call to verify the connection.

## Outbound Calling

Asterisk dials a channel technology and a route, not a number. Bananaflow builds that dial string from the **Dial String Template** on your configuration, replacing `{number}` with the number being called.

The default is `PJSIP/{number}`, which dials a PJSIP endpoint *named after the number*. That is right when your endpoints are the extensions you dial, and wrong on an install whose endpoints are trunks – there, originating `PJSIP/+966500000000` fails with `Allocation failed`, because no endpoint by that name exists.

Pick the template that matches how your dialplan places outbound calls:

| Your Asterisk | Template | Dials |
| - | - | - |
| Endpoints named after extensions | `PJSIP/{number}` | `PJSIP/1001` |
| One outbound trunk | `PJSIP/{number}@my-trunk` | `PJSIP/+966500000000@my-trunk` |
| FreePBX, or any dialplan with outbound routes | `Local/{number}@from-internal` | `Local/+966500000000@from-internal` |

Routing through a `Local` channel is usually the right choice on FreePBX: the call enters your dialplan, and your own outbound routes handle number translation and trunk selection exactly as they do for a deskphone.

<Note>
  A destination that already names a channel technology – `PJSIP/1001@my-trunk`, `Local/1001@from-internal`, `SIP/1001` – is dialed exactly as written, whatever the template says. That is what lets one campaign row or one test call address a specific trunk without changing the configuration.
</Note>

### Campaign contacts

A campaign's `phone_number` column is a destination for this Asterisk, not necessarily a phone number. Extensions (`1001`), SIP URIs (`sip:1001@pbx.local`) and dial strings (`PJSIP/1001@my-trunk`) are all accepted alongside E.164 numbers, and each row goes through the same template above.

Two rules still apply: a destination cannot contain spaces, commas or ampersands, because each of those means something else inside a dial string; and destinations must be unique within a campaign.

<Note>
  Other providers are carriers and reject anything that is not a routable number, so their campaign uploads still require E.164 (`+` and country code). The rule follows the configuration the campaign dials with.
</Note>

## Inbound Calling

Unlike other telephony providers that use HTTP webhooks for inbound calls, ARI delivers inbound calls as **StasisStart events on the ARI WebSocket**. Bananaflow automatically detects these events and activates the workflow assigned to the called extension.

### How It Works

1. An external call arrives at Asterisk and the dialplan routes it into your configuration's Stasis application
2. Asterisk fires a StasisStart event over the ARI WebSocket with the channel in `Ring` state and the dialed extension in the dialplan context
3. Bananaflow looks up the called extension in your telephony configuration's phone numbers, finds the assigned workflow, validates quota, and creates a workflow run
4. The call is answered, bridged to an external media channel, and your voice agent workflow begins

Workflow assignment is **per extension**, so different extensions on the same Asterisk can route to different agents.

### Setting Up Inbound Calls

**Step 1: Configure the Asterisk dialplan**

Ensure your dialplan routes the extensions you care about into the Stasis application you configured in [Part 3](#part-3-route-calls-into-the-stasis-application). Either route a specific extension:

```ini theme={null}
[from-external]
exten => 8000,1,NoOp(Incoming call to 8000)
 same => n,Stasis(bananaflow_a1b2c3d4e5f6)
 same => n,Hangup()
```

…or use a pattern that catches every extension you'll register in Bananaflow:

```ini theme={null}
[from-external]
exten => _X.,1,NoOp(Incoming call to ${EXTEN})
 same => n,Stasis(bananaflow_a1b2c3d4e5f6)
 same => n,Hangup()
```

Replace `bananaflow_a1b2c3d4e5f6` with the **Stasis App Name** shown on your Bananaflow configuration.

**Step 2: Add the extension as a phone number in Bananaflow**

1. Go to **/telephony-configurations** and open your Asterisk ARI configuration
2. In the **Phone numbers** section, add a phone number whose address is the SIP extension (e.g. `8000`)
3. Set its **Inbound workflow** to the agent that should answer
4. Save

   <Note>
     Adding the extension in Bananaflow doesn't change Asterisk's dialplan – that's
     what Step 1 is for. The Bananaflow entry tells the StasisStart handler which
     workflow to run when a call to that extension reaches the Stasis app.
   </Note>

Repeat Step 2 for each extension that should reach a voice agent.

**Step 3: Test an inbound call**

Place a call to one of the extensions you configured. You should see the assigned workflow activate and the voice agent respond.

### Inbound Call Context

When an inbound call activates a workflow, the following context is available to your workflow:

| Field | Description |
| - | - |
| `caller_number` | The caller's phone number or extension |
| `called_number` | The dialed number or extension |
| `direction` | Always `inbound` |
| `call_id` | The Asterisk channel ID |
| `provider` | Always `ari` |

## Troubleshooting

<AccordionGroup>
  <Accordion title="Cannot connect to ARI endpoint">
    * Verify the ARI endpoint URL is correct and reachable from Bananaflow
    * Check that the Asterisk HTTP server is running (`http.conf` has `enabled = yes`)
    * Ensure firewall rules allow traffic on the ARI port (default: 8088)
    * Confirm the ARI module is loaded: run `module show like res_ari` in the Asterisk CLI
  </Accordion>

  <Accordion title="Authentication failed">
    * Verify the ARI Username matches the ARI user section name in `ari.conf`
    * Check the App Password matches the password in `ari.conf`
    * Ensure there are no extra spaces in the credentials
  </Accordion>

  <Accordion title="No audio during calls">
    * Verify `chan_websocket` is loaded: run `module show like chan_websocket` in the Asterisk CLI
    * Check that `websocket_client.conf` is correctly configured with the right Bananaflow URI
    * Ensure the WebSocket Client Name in Bananaflow matches the section name in `websocket_client.conf`
    * Verify network connectivity and firewall rules allow WebSocket traffic between Asterisk and Bananaflow
  </Accordion>

  <Accordion title="Calls not reaching Bananaflow">
    * Ensure the dialplan routes calls to `Stasis(...)` using the **Stasis App Name** from your Bananaflow configuration, not the ARI username
    * Confirm you ran `dialplan reload` after editing `extensions.conf`
    * If two Bananaflow configurations point at this Asterisk, check that they do not name the same Stasis application – the one that connected most recently takes the application over and the other stops receiving calls entirely
    * Check Asterisk CLI for errors: `asterisk -rvvv`
    * Confirm the ARI WebSocket connection is active
  </Accordion>

  <Accordion title="Inbound calls are immediately hung up">
    * Verify the called extension is added as a phone number under your ARI
      configuration in /telephony-configurations and has an **Inbound workflow**
      assigned
    * Confirm the workflow exists and belongs to the same organization as the
      ARI config
    * Check that your organization has available quota
    * Review Bananaflow logs for warnings like "no matching phone number registered
      for config" or "has no inbound\_workflow\_id assigned"
  </Accordion>

  <Accordion title="WebSocket client connection issues">
    * Check the URI in `websocket_client.conf` points to the correct Bananaflow host and port
    * If using TLS, ensure certificates are correctly configured on both sides
  </Accordion>
</AccordionGroup>

## Best Practices

* Keep a low-latency connection between your Asterisk instance and Bananaflow for optimal audio quality
* Use strong passwords for ARI authentication
* Restrict ARI access to known IP addresses using firewall rules
* Monitor Asterisk logs alongside Bananaflow logs when debugging call issues
* Keep Asterisk updated to the latest stable version for security and compatibility

## Further Reading

* [Asterisk Documentation](https://docs.asterisk.org/) -- official reference for all Asterisk configuration
* [ARI Documentation](https://docs.asterisk.org/Configuration/Interfaces/Asterisk-REST-Interface-ARI/) -- detailed ARI configuration and API reference


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.