---
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            |
| `limit`   | number | `20`    | Items per page         |
| `search`  | string | —       | Search by phone number |

### Response

```json
{
  "data": [
    {
      "call_id": "call_abc123",
      "from": "+84901234567",
      "to": "+84909876543",
      "status": "completed",
      "direction": "outbound",
      "duration": 45,
      "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. |

## 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"
        }
      }
    ]
  }'
```

### 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)    |
