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

# Start Stream Call

> Talk to an agent over a WebSocket instead of a phone line: you stream 8 kHz call audio, the agent answers.

Start a call whose audio is a **WebSocket**. Use it when your platform already carries call audio over a WebSocket (a PBX, a telephony platform such as Twilio, Exotel or Klicko, or your own app), or when your network blocks UDP. No phone line and no open UDP ports are needed: everything runs over HTTPS, port 443.

The response is **201 Created** with the call and a one-time `wss://` URL. Whatever streams the audio connects to that URL.

> [!WARNING]
>
> **Call this endpoint from your server.** It needs your API key (scope `agents`). The returned `url` carries no API key, so you can hand it to the component that streams audio.

Costs: AI credits for speech, LLM and memory, like a phone call. No Dialer balance or phone line is used. The workspace must have an active plan.

## Request

### Headers

**Authorization** `string` *required*

Bearer token with your API key (scope `agents`)

**Content-Type** `string` *required*

application/json

### Path

**agentId** `string` *required*

The agent `id` (UUID)

### Body

**overrides** `object`

Per-call settings, as in [Place call](https://docs.60db.ai/api-reference/agents/place-call.md): `call_defaults` fields plus `greeting`, `transfer_targets` and `sentiments`

**metadata** `object`

Your own data, echoed on the call and its events. Up to 4 KB of JSON

## Response

**201 Created**

```json theme={null}
{
  "success": true,
  "data": {
    "call": {
      "id": "6b1f0c52-4d7e-4b8a-9d3e-2a1c8e7f0a11",
      "agent_id": "9c2e1d7a-0b3f-4e6a-8f1d-5a7b9c0e2d44",
      "direction": "stream",
      "to": "stream",
      "from": "stream",
      "status": "dialing",
      "record": false,
      "source": "api"
    },
    "url": "wss://api.60db.ai/ws/agents/stream/6b1f0c52-4d7e-4b8a-9d3e-2a1c8e7f0a11?token=…",
    "expires_in": 55
  }
}
```

The call is trimmed above; see [Get call](https://docs.60db.ai/api-reference/agents/get-call.md) for every field.

* The `url` is **single use** and valid for **55 seconds**. The first connection spends it, right token or not.
* The call moves to `in_progress` when audio starts, and finishes with the usual `call.completed` event.
* A call that never starts (nobody connects, or no valid `start`) ends as `failed` with reason `not_connected`.

## The WebSocket

Connect to `url`, then send `start` within 10 seconds. The socket speaks one of two styles, picked from your **first message**.

### Native style

```json theme={null}
{ "event": "start", "format": "mulaw" }
```

`format` is `mulaw` (G.711 μ-law, 160 bytes per frame) or `pcm16` (signed 16-bit little endian, 320 bytes per frame), both 8 kHz mono. You get `{"event":"started",…}`, then:

* **Audio:** binary messages, 20 ms per frame, in both directions. Send in real time, and send silence while the caller is quiet.
* **Messages from the agent:** `clear` (the caller cut in: drop audio you have not played yet), `dtmf` (`{"digits":"5"}`, the agent pressed a key), `transfer` (`{"destination":"Sales","numbers":["+91…"]}`), `hangup`, and `ended` with the call's summary.
* **Messages from you:** `{"event":"dtmf","digits":"5#"}` (the caller pressed keys), `{"event":"transfer_result","outcome":"joined"}` (`joined`, `busy`, `declined`, `no_answer` or `failed`), `{"event":"stop"}` (the caller hung up).

### Twilio Media Streams style

If your platform already streams the way Twilio Media Streams does (Twilio, Exotel, Klicko and similar), connect the same `url` and send your usual messages: no adapter and no change to the request.

```json theme={null}
{ "event": "connected" }
{ "event": "start", "start": { "streamSid": "MZ…", "mediaFormat": { "encoding": "audio/x-mulaw", "sampleRate": 8000, "channels": 1 } } }
{ "event": "media", "media": { "payload": "<base64 audio>" } }
```

* `mediaFormat` may also sit at the top of `start`, as Klicko sends it.
* Encodings: `audio/x-mulaw`, `pcmu` or `mulaw` (μ-law); `audio/x-l16`, `l16`, `pcm16` or `pcm16_8k` (PCM16). The rate must be 8000. Other formats (`pcma`, 16 kHz) close the socket with `1008`.
* You get `media`, `clear` and `stop` back in the same style, plus the agent's `dtmf`, `transfer`, `hangup` and `ended` messages. There is no `started` reply, and `mark` is ignored.
* Base64 in JSON is about 1.7 times the bytes of the native style. Prefer native when you control both ends.

### Rules

* Keep every message under **4 KB**. Larger ones close the socket.
* A connection silent for 45 seconds is closed (it is pinged every 15 seconds).
* Transfers: put the caller through on your own platform, then reply with `transfer_result` within 10 seconds. Without a reply the caller is taken to be with the person.

## Limits

* Up to 3 stream calls at once per workspace, including calls still waiting for their socket.
* Call length up to 900 seconds (`max_duration_secs`).
* No phone line, so no caller ID and no line quality (jitter or packet loss) in [call measurements](https://docs.60db.ai/features/agents.md#call-measurements).

## Errors

| Status | Code | Meaning |
| - | - | - |
| 400 | `VALIDATION_ERROR` | A field is invalid. `field` names it |
| 402 | `INSUFFICIENT_CREDITS` | Not enough AI credits to start a call |
| 403 | `POLICY_DENY` | No active plan, or the API key lacks the `agents` scope |
| 404 | `AGENT_NOT_FOUND` | No agent with this ID in your workspace |
| 429 | `CONCURRENCY_LIMIT` | 3 stream calls are already running |

| Close code | Meaning |
| - | - |
| `1000` | The call ended normally |
| `1002` | A malformed or unknown message (native style) |
| `1008` | Invalid or expired URL, no valid `start` within 10 s, or an unsupported audio format |
| `1009` | A message over 4 KB |
| `1011` | The call service failed |


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