---
sidebar_position: 2
title: Call
description: Make, receive, and control calls programmatically via the Firetell Call API.
---

# Call

The Call API allows you to initiate outbound server-to-server calls, control active calls with actions, and retrieve call history.

## Endpoints

| Method | Endpoint             | Description                      |
| ------ | -------------------- | -------------------------------- |
| `GET`  | `/calls`             | List call history                |
| `GET`  | `/calls/:id/events`  | Get call events timeline         |
| `POST` | `/calls/make`        | Initiate an outbound call        |
| `PUT`  | `/calls/:id/actions` | Update actions on an active call |

## List Call History

Returns paginated call history for your workspace. Requires `ApiKey` with any scope.

```http
GET /calls?page=1&limit=20
```

### Query Parameters

| Parameter   | Type   | Default | Description                                                                                 |
| ----------- | ------ | ------- | ------------------------------------------------------------------------------------------- |
| `page`      | number | `1`     | Page number (min: 1)                                                                        |
| `limit`     | number | `20`    | Items per page (max: 100)                                                                   |
| `search`    | string | —       | Search by phone number or party name                                                        |
| `direction` | string | `all`   | Filter by call direction: `inbound`, `outbound`, `internal`, `all`                           |
| `status`    | string | `all`   | Filter by call status: `answered`, `completed`, `active`, `failed`, `no_answer`, `busy`, etc.|
| `from`      | string | —       | Filter by caller phone number or username                                                   |
| `to`        | string | —       | Filter by destination phone number or username                                              |
| `sentiment` | string | `all`   | Filter by AI sentiment analysis: `positive`, `neutral`, `negative`, `all`                   |

### Response

```json
{
  "data": [
    {
      "id": "call_01h900000000000000000001",
      "workspace_id": "ws_123456789",
      "number": "18005550199",
      "from": {
        "name": "Support Agent 1",
        "number": "agent1001"
      },
      "to": {
        "name": "Customer",
        "number": "14155552671"
      },
      "status": "completed",
      "direction": "outbound",
      "duration": 45,
      "billsec": 42,
      "recording": "ready",
      "transcription": "completed",
      "sentiment": "positive",
      "summary": "Customer reached out to inquire about smart call center solutions.",
      "action_items": ["Send Enterprise plan quotation", "Schedule system demo"],
      "created_at": "2026-07-09T10:00:00Z"
    }
  ],
  "meta": {
    "total": 100,
    "page": 1,
    "limit": 20,
    "total_pages": 5
  }
}
```

## Make a Call

Initiate an outbound server-to-server call. Requires `ApiKey` with `full` scope.

```http
POST /calls/make
```

### Request Body

| Field          | Type   | Required | Description                                                                                                                                                      |
| -------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `to`           | object | ✅       | Destination party `{ number, name? }`. Number can be an E.164 phone number, extension, or agent username.                                                        |
| `to.number`    | string | ✅       | Destination phone number (E.164), extension, or username (3-30 chars).                                                                                           |
| `to.name`      | string | —        | Display name for the callee (up to 64 chars). Fallbacks to `to.number` if omitted.                                                                               |
| `from`         | object | —        | Caller party `{ number, name? }`. Phone number (E.164) or agent username.                                                                                        |
| `from.number`  | string | ✅       | Caller ID phone number (E.164) or agent username (3-30 chars).                                                                                                   |
| `from.name`    | string | —        | Display name for the caller / CNAM (up to 64 chars). Fallbacks to `from.number` if omitted.                                                                      |
| `call_flow_id` | string | —        | Call flow to execute on answer (mutually exclusive with `actions`).                                                                                              |
| `max_duration` | number | —        | Maximum call duration limit in seconds (1 to 7200). The call automatically hangs up after this duration. Default: based on credit & platform safety cap (7200s). |
| `actions`      | array  | —        | Array of actions to perform sequentially when the call connects (mutually exclusive with `call_flow_id`).                                                        |

:::tip
**Auto-Hangup on Flow Completion**

When executing sequential actions (e.g. playing an audio announcement or TTS notification), Firetell **automatically hangs up the call (`NORMAL_CLEARING`)** as soon as the last action in the list finishes executing. You do not need to explicitly append a `hangup` or `disconnect` action unless you want to terminate earlier.
:::

### Call Actions

Each action object has the following shape:

| Field         | Type    | Required | Description                                  |
| ------------- | ------- | -------- | -------------------------------------------- |
| `action`      | string  | ✅       | Action type (see below)                      |
| `params`      | object  | —        | Action-specific parameters                   |
| `continue`    | boolean | —        | Whether to continue to the next action       |
| `auto_answer` | boolean | —        | Auto-answer the call before executing action |

### Action Reference

All server-to-server actions are unified with Call Flow builder actions for structural consistency.

#### `play` — Audio Playback

Play a pre-uploaded workspace audio file.

| Param              | Type    | Required | Description                                                                              |
| ------------------ | ------- | -------- | ---------------------------------------------------------------------------------------- |
| `audio_id`         | string  | ✅       | ID of the workspace audio asset to play                                                  |
| `answer_call`      | boolean | —        | Whether to answer the call before playing. Default: `true`                               |
| `continue_on_play` | boolean | —        | If `true`, playback runs in background while the next action executes. Default: `false`. |

#### `tts` — Text-to-Speech

Play a synthesized speech message.

| Param   | Type   | Required | Description                |
| ------- | ------ | -------- | -------------------------- |
| `text`  | string | ✅       | The text to read aloud     |
| `voice` | string | —        | Synthetic voice identifier |
| `speed` | number | —        | Voice speaking speed rate  |

#### `ivr` — Wait for Digits

Wait for the callee to press DTMF keys.

| Param         | Type   | Required | Description                                                   |
| ------------- | ------ | -------- | ------------------------------------------------------------- |
| `timeout`     | number | —        | Time in seconds to wait for input. Default: `5`               |
| `max_digits`  | number | —        | Maximum digits to collect (between 1-10). Default: `1`        |
| `webhook_url` | string | ✅       | The POST destination URL where collected digits will be sent. |

##### Collected Callback Payload

When DTMF collection completes (due to timeout, reaching max digits, or pressing `#`), Firetell dispatches a queued POST request to your `webhook_url` with the following JSON payload:

```json
{
  "event": "call.ivr_collected",
  "data": {
    "workspace_id": "ws_xyz789",
    "call_id": "call_abc123",
    "digits": "123",
    "status": "completed" // "completed" or "timeout"
  }
}
```

#### `to_operator` — Connect External Phone

Bridge the call to an external phone number or direct SIP URI via carrier gateway.

| Param               | Type   | Required | Description                                                                                                                                                 |
| ------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `phone_number`      | string | ✅       | Destination E.164 phone number or direct SIP URI                                                                                                            |
| `from`              | string | —        | Custom DID phone number (E.164) used as caller ID. Automatically resolves the matching carrier gateway to prevent cross-carrier blockage. Default: Call DID |
| `timeout`           | number | —        | Timeout in seconds for the ringing phase. Default: `30`                                                                                                     |
| `ringback_audio_id` | string | —        | Audio file ID to play as hold music while ringing                                                                                                           |

#### `connect_agent` — Connect Agent

Bridge the call to a registered Firetell agent.

| Param               | Type   | Required | Description                                       |
| ------------------- | ------ | -------- | ------------------------------------------------- |
| `agent_id`          | string | ✅       | Unique registered agent ID                        |
| `timeout`           | number | —        | Timeout in seconds. Default: `30`                 |
| `ringback_audio_id` | string | —        | Audio file ID to play as hold music while ringing |

#### `connect_team` — Connect Team Queue

Bridge the call to a queue team.

| Param               | Type   | Required | Description                                       |
| ------------------- | ------ | -------- | ------------------------------------------------- |
| `team_id`           | string | ✅       | Unique registered team ID                         |
| `timeout`           | number | —        | Timeout in seconds. Default: `30`                 |
| `ringback_audio_id` | string | —        | Audio file ID to play as hold music while ringing |

#### `connect_voice_agent` — Connect Voice AI Agent

Bridge the call to a Realtime Conversational Voice AI Agent.

| Param                  | Type   | Required | Description                                                                                            |
| ---------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------ |
| `voice_agent_id`       | string | ✅       | Unique Voice Agent ID (`va_...`)                                                                       |
| `version`              | number | —        | Specific agent version number (e.g. `1`). Defaults to the current active published version if omitted. |
| `timeout`              | number | —        | Ringing timeout in seconds before fallback. Default: `30`                                              |
| `max_duration_seconds` | number | —        | Maximum duration limit in seconds for the Voice AI session. Default: `300`                             |
| `ringback_audio_id`    | string | —        | Audio file ID to play as hold music while establishing connection                                      |

#### `voicemail` — Voicemail Recording

Record a voicemail message from the caller and automatically upload it to Firetell Cloud Storage.

| Param               | Type    | Required | Description                                                              |
| ------------------- | ------- | -------- | ------------------------------------------------------------------------ |
| `greeting_audio_id` | string  | —        | Pre-recorded greeting file ID. Fallbacks to default greeting if omitted. |
| `max_duration`      | number  | —        | Max recording length in seconds. Default: `60`                           |
| `beep`              | boolean | —        | Whether to play a tone beep before starting recording. Default: `true`   |

#### `disconnect` / `hangup` — Hang Up

Terminate the active call channel. Either name can be used interchangeably.

| Param   | Type   | Required | Description                                    |
| ------- | ------ | -------- | ---------------------------------------------- |
| `cause` | string | —        | SIP hangup reason (default: `NORMAL_CLEARING`) |

#### `recording` — Call Session Recording

Record the entire call session and automatically upload the file to S3 cloud storage.

:::caution
This action will be automatically ignored and skipped if the workspace plan quota does not authorize call recording (specifically, `call_recording` for app-to-phone external calls, or `call_internal_recording` for app-to-app internal calls). In this case, the call flow will seamlessly proceed to the next action.
:::

| Param         | Type    | Required | Description                                                                                                |
| ------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `format`      | string  | —        | Audio format: `wav` (default) or `mp3`.                                                                    |
| `stereo`      | boolean | —        | Whether to record caller and callee on separate stereo channels (left/right). Default: `false`.            |
| `answer_call` | boolean | —        | Whether to answer the call immediately (`true`, default). Set to `false` to defer recording until bridged. |

#### `stream` — Audio Stream Fork

Fork the call audio in real-time to your own WebSocket server. Useful for building custom voice bots, real-time translation, call analytics, or any scenario where your server needs raw audio access during the call.

| Param           | Type    | Required | Description                                                                                                                          |
| --------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `ws_url`        | string  | ✅       | Destination WebSocket URL (`wss://` or `ws://`). Must be a publicly accessible server.                                               |
| `track`         | string  | —        | Audio legs to fork: `both` (default, stereo — caller on left, callee on right), `inbound` (caller only), `outbound` (callee only). |
| `sample_rate`   | number  | —        | PCM audio sample rate in Hz: `8000` (default, G.711 compatible) or `16000` (wideband).                                             |
| `bidirectional` | boolean | —        | If `true`, audio sent from your WS server back to Firetell is played into the call channel in real-time (default: `false`).         |
| `answer_call`   | boolean | —        | Answer the call before starting the stream. Default: `true`. Set to `false` only if the call was already answered by a prior `answer` action — audio will not flow until the channel is answered, regardless of whether the WebSocket connection to your server is established. |
| `headers`       | object  | —        | Custom HTTP headers to include in the WebSocket handshake (e.g. `{ "Authorization": "Bearer token" }`). Max 10 headers.            |

:::info
**Bidirectional Audio**

When `bidirectional: true` your server receives the caller's raw PCM audio and can send audio frames back in real-time. Firetell injects those frames directly into the caller's audio channel. This lets you build a fully custom voice bot, live interpreter, or real-time TTS system using the transport of your choice.

When `bidirectional: false` the `stream` action only *sends* audio to your server. The call flow continues normally, and your server can consume the audio stream for transcription, recording, or analytics without affecting the call.
:::

:::caution
**`bidirectional: true` requires the call to be answered.**

Firetell only generates audio write frames (needed to play audio back to the caller) on channels that are in the `ACTIVE` (answered) state. If the call is not answered, your server will receive the connection but audio sent from your server **will not be played** to the caller.

Always use `answer_call: true` (the default) when `bidirectional: true`, or ensure the call was answered by a prior `answer` action in the flow.

**Security notice**: Only `wss://` and `ws://` URLs pointing to publicly routable IP addresses are accepted. Internal addresses (RFC 1918, loopback, link-local, cloud metadata) are blocked.
:::


## Use Cases & Examples

### 1. Simple Outbound Call — Connect to Agent

Call an external number and connect directly to an agent when answered.

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Customer Support"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "actions": [
      {
        "action": "connect_agent",
        "params": {
          "agent_id": "agt_abc123",
          "timeout": 30
        }
      }
    ]
  }'
```

### 2. Outbound Call with Hold Music

Call an external number and play hold music while the agent is ringing. The music stops automatically when the agent answers.

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Customer Support"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "actions": [
      {
        "action": "connect_agent",
        "params": {
          "agent_id": "agt_abc123",
          "timeout": 30,
          "ringback_audio_id": "aud_holdmusic"
        }
      }
    ]
  }'
```

:::tip
The `ringback_audio_id` param works on `connect_agent`, `connect_team`, `connect_voice_agent`, and `to_operator`. Upload your hold music via the [Audio API](/docs/rest-api/workspace-api/audios) first to get the `audio_id`.
:::

### 3. Agent Cascade — Sequential Fallback

Try agent 1 first. If they don't answer within 10 seconds, automatically try agent 2. If agent 2 also doesn't answer, route to the support team.

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Customer Support"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "actions": [
      {
        "action": "connect_agent",
        "params": {
          "agent_id": "agt_primary",
          "timeout": 10,
          "ringback_audio_id": "aud_holdmusic"
        }
      },
      {
        "action": "connect_agent",
        "params": {
          "agent_id": "agt_backup",
          "timeout": 10,
          "ringback_audio_id": "aud_holdmusic"
        }
      },
      {
        "action": "connect_team",
        "params": {
          "team_id": "team_support",
          "timeout": 30,
          "ringback_audio_id": "aud_holdmusic"
        }
      },
      {
        "action": "voicemail",
        "params": {
          "greeting_audio_id": "aud_vm_greeting",
          "max_duration": 60
        }
      }
    ]
  }'
```

:::info
Actions execute **sequentially**. If a `connect_*` action fails (no answer, timeout, agent offline), the system automatically falls through to the next action in the array.
:::

### 4. Recorded Outbound Campaign

Make an outbound call with recording enabled, play a TTS message, then hang up. Useful for automated notification campaigns.

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Customer Support"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "actions": [
      {
        "action": "recording",
        "params": {
          "format": "wav",
          "stereo": false
        }
      },
      {
        "action": "tts",
        "params": {
          "text": "Hello, this is a unified notification from your system."
        }
      },
      {
        "action": "disconnect"
      }
    ]
  }'
```

:::caution
The `recording` action is automatically skipped if your workspace plan does not include the `call_recording` quota. The remaining actions will still execute normally.
:::

### 5. Automated Voice Broadcast / Order Notification

Make an automated announcement call. The call plays the order status audio file and **automatically hangs up** as soon as the playback finishes. Setting `max_duration: 60` enforces an absolute safety cap of 60 seconds.

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Firetell Delivery"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "max_duration": 60,
    "actions": [
      {
        "action": "play",
        "params": {
          "audio_id": "au_41817c09bc4d27a405ec5a",
          "answer_call": true,
          "continue_on_play": false
        }
      }
    ]
  }'
```

### 6. Outbound AI Voice Agent Call

Initiate an automated outbound call directly connected to a Realtime Voice AI Agent (e.g. appointment confirmation, customer survey, or booking assistant).

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Virtual Clinic Assistant"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "max_duration": 300,
    "actions": [
      {
        "action": "connect_voice_agent",
        "params": {
          "voice_agent_id": "va_01h900000000000000000001",
          "version": 1,
          "timeout": 30
        }
      }
    ]
  }'
```

### 7. Mid-Call Action Update

After a call is in `started` or `active` status, you can dynamically push new actions using the [Update Call Actions](#update-call-actions) endpoint. This is useful for interactive scenarios where your backend decides the next step based on external logic or customer input.

```bash
# Step 1: Initiate the call
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "Customer Support"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "actions": [
      {
        "action": "play",
        "params": { "audio_id": "aud_welcome" }
      }
    ]
  }'
# Returns: { "data": { "call_id": "call_abc123", ... } }

# Step 2: After your backend logic, dynamically hand over the active call to a Voice AI Agent
curl -X PUT "https://{workspace_id}.firetell.app/api/v1/calls/call_abc123/actions" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "actions": [
      {
        "action": "connect_voice_agent",
        "params": {
          "voice_agent_id": "va_01h900000000000000000001"
        }
      }
    ]
  }'
```

### 8. Custom Voice Bot via Audio Stream

Fork the call audio in real-time to your own WebSocket server. Your server receives raw PCM audio and can send synthesized speech back into the call channel. This pattern is ideal when you want full control over the AI model, TTS provider, or business logic without using Firetell's built-in Voice Agent.

> 📦 **Sample code**: [Node.js](https://github.com/firetellcom/audio-stream-nodejs-example) · [Python](https://github.com/firetellcom/audio-stream-python-example)

```bash
curl -X POST "https://{workspace_id}.firetell.app/api/v1/calls/make" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "number": "+84901234567",
      "name": "VoiceBot Support"
    },
    "to": {
      "number": "+84909876543",
      "name": "John Doe"
    },
    "actions": [
      {
        "action": "stream",
        "params": {
          "ws_url": "wss://your-bot-server.example.com/call-stream",
          "track": "both",
          "sample_rate": 8000,
          "bidirectional": true,
          "headers": {
            "Authorization": "Bearer your-api-token",
            "X-Bot-Version": "v2"
          }
        }
      }
    ]
  }'
```

**WebSocket protocol on your server side:**

| Direction | Frame type | Content |
|-----------|----------|--------|
| Firetell → Your server | Binary | PCM audio at `sample_rate` Hz (stereo if `track=both`: caller on left, callee on right) |
| Your server → Firetell | Binary | Mono PCM audio at `sample_rate` Hz — played back to the caller in real-time (requires `bidirectional: true`) |
| Your server → Firetell | Text (JSON) | `{"type":"killAudio"}` — instructs Firetell to immediately stop any queued audio playback (barge-in) |

:::tip
`call_id`, `workspace_id`, `caller_number`, `caller_name`, `destination_number`, and `stream_type=firetell_stream` are automatically appended to your `ws_url` as query parameters so your server can identify the call and caller without needing custom headers.
:::

### Response

All `POST /calls/make` requests return:

```json
{
  "data": {
    "call_id": "call_abc123",
    "status": "created",
    "direction": "outbound",
    "from": {
      "name": "Customer Support",
      "number": "+84901234567"
    },
    "to": {
      "name": "John Doe",
      "number": "+84909876543"
    },
    "job_id": "job_xyz789",
    "job_status": "queued"
  }
}
```

## Update Call Actions

Update the actions on an active call. Requires `ApiKey` with `full` scope.

The call must be in `started` or `active` status, and the media channel must be ready.

```http
PUT /calls/:id/actions
```

### Request Body

| Field     | Type  | Required | Description                                                                                                                 |
| --------- | ----- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `actions` | array | ✅       | Array of call action objects (minimum 1). See [Action Reference](#action-reference) above for available actions and params. |

### Example Request

```bash
curl -X PUT "https://{workspace_id}.firetell.app/api/v1/calls/call_abc123/actions" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "actions": [
      {
        "action": "tts",
        "params": { "text": "Your order has been confirmed. Goodbye!" },
        "continue": true
      },
      {
        "action": "disconnect"
      }
    ]
  }'
```

### Response

```json
{
  "data": {
    "call_id": "call_abc123",
    "queued": true,
    "action_count": 2
  }
}
```

## Get Call Events

Retrieve the event timeline for a specific call, sorted chronologically. Requires `ApiKey` with any scope.

```http
GET /calls/:id/events?page=1&limit=50
```

### Response

```json
{
  "data": [
    {
      "id": "evt_abc123",
      "call_id": "call_abc123",
      "event": "call.created",
      "direction": "outbound",
      "sip_code": null,
      "to": {
        "number": "+84909876543",
        "name": "John Doe"
      },
      "created_at": "2026-07-09T10:00:00Z"
    },
    {
      "id": "evt_abc124",
      "call_id": "call_abc123",
      "event": "call.ringing",
      "direction": "outbound",
      "sip_code": null,
      "to": {
        "number": "+84909876543",
        "name": "John Doe"
      },
      "created_at": "2026-07-09T10:00:02Z"
    },
    {
      "id": "evt_abc125",
      "call_id": "call_abc123",
      "event": "call.answered",
      "direction": "outbound",
      "sip_code": 200,
      "to": {
        "number": "+84909876543",
        "name": "John Doe"
      },
      "created_at": "2026-07-09T10:00:05Z"
    },
    {
      "id": "evt_abc126",
      "call_id": "call_abc123",
      "event": "call.ended",
      "direction": "outbound",
      "sip_code": 200,
      "hangup_cause": "NORMAL_CLEARING",
      "created_at": "2026-07-09T10:00:50Z"
    }
  ],
  "meta": {
    "total": 4,
    "page": 1,
    "limit": 50,
    "total_pages": 1
  }
}
```

### Event Types

| Event                          | Description                                       |
| ------------------------------ | ------------------------------------------------- |
| `call.created`                 | Call channel created                              |
| `call.answered`                | Call was answered                                 |
| `call.bridged`                 | Two call legs bridged together                    |
| `call.ended`                   | Call hangup completed                             |
| `call.destroyed`               | Call channel destroyed                            |
| `call.dtmf`                    | DTMF digit received                               |
| `call.playback_started`        | Audio playback started                            |
| `call.playback_stopped`        | Audio playback stopped                            |
| `call.recording.started`       | Call recording stream started (In-Call SSE)       |
| `call.recording.completed`     | Call recording stream completed (In-Call SSE)     |
| `call.recording.ready`         | Call recording uploaded and ready (Webhook & SSE) |
| `call.transcription.dialogue`  | Live speech transcription utterance (In-Call SSE) |
| `call.transcription.completed` | Call transcription with NER entities (Webhook)    |
