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

# Web Call SDK API reference

> Reference for the Bolna Web Call SDK: BolnaWebCall constructor options, start and stop methods, events, call states, error codes and the session object.

Reference for `@bolna/web-call`. For setup and a quickstart, see [Web Call SDK](/docs/developer-resources/sdks/web-call).

## Constructor

`new BolnaWebCall(options)`: Provide **exactly one** session source. The constructor throws if you pass zero or more than one.

| Option | Type | Use when |
| - | - | - |
| `sessionUrl` | `string` | You have a backend route (POST, body is `{}` or `{ user_data }` when `userData` is set) returning the mint JSON. This is the standard setup. |
| `getSession` | `() => Promise<Session>` | You need custom fetch logic: extra auth headers, retries, a framework's HTTP client. |
| `session` | `Session` | You already have a freshly-minted session in hand. It expires in \~120s and is single-use. |

Optional, on top of one of the three above:

| Option | Default | Purpose |
| - | - | - |
| `userData` | none | Per-call variables substituted into the agent's prompt and welcome message, identical to telephony's `user_data`. See [Passing user data](/docs/developer-resources/sdks/web-call#passing-user-data). |
| `audio` | AEC / NS / AGC on | `MediaTrackConstraints` for the microphone. |
| `iceTransportPolicy` | `"all"` | `"relay"` forces TURN. Useful for testing on known-restrictive networks. |
| `audioElement` | hidden element created for you | Play the agent's audio through an `<audio>` element you control. |
| `debug` | `false` | Verbose console logging of state transitions. |

## Methods

| Method | Description |
| - | - |
| `await call.start(opts?)` | Mints a session, requests mic permission, connects. Pass `{ userData }` to set or override per-call variables for just this call. Resolves once the agent answers. Call it from a user gesture (a click handler) so the browser allows audio playback. |
| `await call.stop()` | Hangs up and releases the microphone, audio element, and connection watchers. Safe to call from any state. |
| `call.setMuted(bool)` | Toggles the local mic track without ending the call. |
| `call.isMuted()` | Returns the current mute state. |
| `call.getState()` | Returns the current `CallState` (see below), the same value `state-change` just emitted. |
| `call.getRunId()` | The call's execution id, set once `start()` mints a session. Matches the id in your Bolna call history and webhooks. |

## Call state

```mermaid theme={"system"}
flowchart LR
    idle --> connecting --> ringing --> active --> ended
```

A fresh `start()` is allowed again once state reaches `ended`. Each call gets its own freshly-minted session.

## Events

Subscribe with `call.on(event, handler)`, and remove a handler with `off` or `once` for a one-time listener.

| Event | Payload | Fires when |
| - | - | - |
| `state-change` | `CallState` | Any transition between the five states above. |
| `media-permission` | none | The browser granted microphone access. |
| `call-start` | none | The agent answered. Audio is flowing both ways. |
| `call-end` | `{ reason }` | `"local-hangup"`, `"remote-hangup"`, or `"failed"`. |
| `error` | `{ code, message, scope?, cause? }` | See the error table below. |
| `volume-level` | `number` (0 to 1) | Agent audio level, about 10 times a second while active. Use it to drive a meter or avatar. |

<Note>
  A handler that throws is caught internally and logged. It can't take down call handling or other listeners.
</Note>

<Note>
  `cause` holds the underlying error when one exists, for example a `DOMException` from a denied `getUserMedia()` call, or the raw error from a failed `fetch()`. It's for logging and debugging: untyped (`unknown`), and not guaranteed to be present.
</Note>

## Error codes

| Code | Meaning | Typical handling |
| - | - | - |
| `mint_failed` | Your session endpoint errored or returned an unexpected shape. | Check your backend route and network tab. |
| `at_capacity` | Concurrent-call limit hit. `scope` is `"global"`, `"customer"`, or `"not_enabled"`. | Show "all lines busy, try again shortly." |
| `microphone_denied` | The user blocked microphone access. | Show mic-permission help for their browser. |
| `connect_failed` | Network or server unreachable, or the call setup timed out (30s). | Retry with a fresh `start()`. |
| `call_rejected` | The server declined the call before it connected. | Check the agent id and session freshness. |
| `autoplay_blocked` | The browser blocked audio playback. | Ensure `start()` is called from a click handler. |
| `already_active` | `start()` was called while a call was already live. | One call per `BolnaWebCall` instance at a time. |

## Session shape

If you use `getSession` instead of `sessionUrl`, resolve to this shape. It's exactly what Bolna's mint endpoint returns, so most integrations never construct it by hand: your backend proxies the mint response as-is.

```typescript theme={"system"}
interface Session {
  run_id: string;
  agent_id: string;
  sip_username: string;
  sip_password: string;
  sip_domain: string;
  wss_url: string;
  sip_register: boolean; // internal connection flag, pass it through unchanged
  expires_in: number;    // seconds, treat as ~120s and fetch a fresh one per call
  ice_servers: RTCIceServer[];
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Take calls in the browser" href="/docs/developer-resources/sdks/web-call" />
</CardGroup>


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