---
sidebar_position: 4
title: API Reference
description: Detailed API reference for the Firetell Flutter SDK classes, methods, and types.
---

# API Reference

This document provides a detailed description of the classes, methods, streams, and types exposed by `firetell_flutter_sdk`.

---

## FiretellClient

The main client managing session initialization, REST call dispatch, SSE event streaming, and active call lifecycle.

### Constructor

```dart
FiretellClient({
  required String jwt,
  required String domain,
})
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `jwt` | `String` | Agent JWT authentication token |
| `domain` | `String` | Workspace API domain (e.g. `yourcompany.firetell.app`) |

---

### Properties

#### `ready`

- **Type:** `Future<Session>`
- **Description:** Resolves when workspace metadata is fetched, SSE stream is connected, and the session is ready.

#### `isConnected`

- **Type:** `bool`
- **Description:** Returns `true` if the SSE event stream is currently connected.

#### `activeCalls`

- **Type:** `Map<String, Call>`
- **Description:** Map of currently active calls, keyed by call ID.

#### `iceServers`

- **Type:** `List<Map<String, dynamic>>`
- **Description:** ICE servers from workspace metadata (or defaults).

#### `baseUrl`

- **Type:** `String`
- **Description:** Workspace base URL.

#### `jwt`

- **Type:** `String`
- **Description:** Current JWT token.

#### `session`

- **Type:** `Session?`
- **Description:** Current session info. `null` before authentication or after logout.

---

### Event Streams

| Stream | Type | Description |
|--------|------|-------------|
| `onCallRing` | `Stream<CallRingParams>` | Incoming call ring notification (from SSE) |
| `onCallOffer` | `Stream<Call>` | Incoming call with WebRTC ready to answer |
| `onCallCreated` | `Stream<Map<String, dynamic>>` | New call created in workspace |
| `onCallStarted` | `Stream<Map<String, dynamic>>` | Call ringing at destination |
| `onCallAnswered` | `Stream<Map<String, dynamic>>` | Call answered |
| `onCallEnded` | `Stream<Map<String, dynamic>>` | Call ended |
| `onCallCanceled` | `Stream<Map<String, dynamic>>` | Call canceled before answer |
| `onAgentState` | `Stream<Map<String, dynamic>>` | Agent state changed |
| `onSession` | `Stream<Session?>` | Session state changed |
| `onError` | `Stream<Object>` | Error event |
| `onConnectionState` | `Stream<SseConnectionState>` | SSE connection state changes |

---

### Methods

#### `makeOutboundCall()`

```dart
Future<Call> makeOutboundCall({
  required String to,
  String? from,
  bool isVideo = false,
})
```

Creates a `Call`, sets up WebRTC media, gathers Full ICE candidates, calls the REST API, connects the per-call WebSocket, and sends the SDP offer.

#### `getPhoneNumbers()`

```dart
Future<List<PhoneNumber>> getPhoneNumbers({int page = 1, int limit = 100})
Future<PhoneNumbersResponse> getPhoneNumbersResponse({int page = 1, int limit = 100})
```

Fetch phone numbers (DIDs) accessible by the authenticated agent/team from `GET /api/v1/call-center/phone-numbers`. Use the returned number as `from` (Caller ID) in `makeOutboundCall`.

#### `handlePushIncomingCall()`

```dart
Future<Call> handlePushIncomingCall(CallRingParams params)
```

Creates a `Call` from push notification parameters and connects the signaling WebSocket. The call is **not** auto-answered — call `call.accept()` when the user taps answer.

#### `sendTransfer()`

```dart
Future<void> sendTransfer(String callId, String target, {String? reason})
```

Transfer a call via WebSocket (if active) or REST API fallback.

#### `logout()`

```dart
Future<void> logout({String? deviceId})
```

Unregisters the device push token on the backend (`POST /api/v1/me/logout`), hangs up all active calls, closes the SSE stream, and cleans up the local session. Defaults to `DeviceIdHelper.getOrCreate()` if `deviceId` is omitted.

#### `destroy()`

Fully destroys the client immediately without server communication.

---

## Call

Represents a single VoIP call session with dedicated WebSocket signaling and WebRTC peer connection.

### Constructor

```dart
Call({
  required List<Map<String, dynamic>> iceServers,
  CallOptions options = const CallOptions(),
})
```

### Properties

| Property | Type | Description |
|----------|------|-------------|
| `callId` | `String?` | Unique call identifier |
| `to` | `String` | Destination number/extension |
| `from` | `String` | Caller number/extension |
| `fromName` | `String` | Caller display name |
| `callState` | `CallState` | Current call state |
| `active` | `bool` | Whether the call is currently active |
| `isVideo` | `bool` | Whether the call includes video |
| `isCameraOff` | `bool` | Whether local camera transmission is disabled/muted |
| `isMuted` | `bool` | Whether the microphone is muted |
| `isSpeakerOn` | `bool` | Whether audio is routed to speakerphone (vs earpiece) |
| `isHold` | `bool` | Whether the call is on hold |

### Event Streams

| Stream | Type | Description |
|--------|------|-------------|
| `onStateChange` | `Stream<({CallState state, String? reason, Map<String, dynamic>? data})>` | Call state changes |
| `onLocalStream` | `Stream<MediaStream?>` | Local camera/microphone media stream |
| `onRemoteStream` | `Stream<MediaStream?>` | Remote audio/video stream |
| `onMuteChange` | `Stream<bool>` | Microphone mute state changes |
| `onCameraChange` | `Stream<bool>` | Camera state changes (`true` = off, `false` = on) |
| `onSpeakerChange` | `Stream<bool>` | Speakerphone state changes |

### Methods

#### `accept()`

```dart
Future<void> accept()
```

Accept an incoming call — sets up WebRTC media (audio and video if SDP contains video), creates SDP answer, gathers Full ICE candidates, and sends the answer via WebSocket.

#### `reject()`

```dart
Future<void> reject()
```

Reject an incoming call via WebSocket.

#### `rejectViaHttp()`

```dart
Future<void> rejectViaHttp({
  required String baseUrl,
  required String callToken,
})
```

Reject via fast HTTP endpoint (~50ms). Preferred for push-triggered reject when no WebSocket is connected.

#### `hangup()`

```dart
Future<void> hangup()
```

End the active call. Sends `call.hangup` via WebSocket and cleans up WebRTC resources.

#### `mute()` / `unmute()` / `toggleMute()`

```dart
Future<void> mute()
Future<void> unmute()
Future<void> toggleMute()
```

#### `muteVideo()` / `unmuteVideo()` / `toggleCamera()`

```dart
Future<void> muteVideo()
Future<void> unmuteVideo()
Future<void> toggleCamera()
```

Mute or resume local video track transmission and notify remote peer via `call.camera`.

#### `switchCamera()`

```dart
Future<void> switchCamera()
```

Switch between the front-facing and rear-facing device cameras.

#### `setSpeakerphoneOn()` / `toggleSpeaker()`

```dart
Future<void> setSpeakerphoneOn(bool enable)
Future<void> toggleSpeaker()
```

Toggle audio output between the device speakerphone (loudspeaker) and earpiece.

#### `onhold()` / `unhold()`

```dart
Future<void> onhold()
Future<void> unhold()
```

Hold/unhold via SDP renegotiation (changes transceiver direction, re-gathers ICE, sends new SDP).

#### `sendDTMF()`

```dart
void sendDTMF(String digit)
```

Send a DTMF digit (`0-9`, `*`, `#`, `A-D`).

#### `transfer()`

```dart
Future<void> transfer(String target, {String? reason})
```

Transfer the call to another target (extension, phone number, team ID, SIP account).

#### `connectSignaling()`

```dart
Future<void> connectSignaling(String wsUrl, String callToken)
```

Connect the per-call WebSocket and authenticate with `call_token`. Must complete within 3 seconds.

#### `destroy()`

```dart
void destroy({bool sendHangup = true})
```

Clean up all resources (WebSocket, WebRTC, streams).

---

## Models

### `Session`

```dart
class Session {
  final String sessionId;
  final String username;
  final String displayName;
  final String domain;
  final int expiresAt; // Unix timestamp in milliseconds
}
```

### `CallOptions`

```dart
class CallOptions {
  final String to;
  final String from;
  final String fromName;
  final String? fromAvatar;
  final bool isVideo;
  final bool isTransfer;
  final String? transferReason;
}
```

### `CallRingParams`

```dart
class CallRingParams {
  final String callId;
  final String callToken;
  final String? wsUrl;
  final String callerNumber;
  final String callerName;
  final String? callerAvatar;
  final String calleeNumber;
  final String calleeName;
  final bool isTransfer;
  final String? transferReason;
  final bool isVideo;
  final int ringTimeoutSecs;
}
```

Factory constructors:

```dart
CallRingParams.fromFcmData(Map<String, dynamic> data)
CallRingParams.fromApnsPayload(Map<String, dynamic> payload)
CallRingParams.fromMap(Map<String, dynamic> map)
```

### `MakeCallResponse`

```dart
class MakeCallResponse {
  final String callId;
  final String callToken;
  final String wsUrl;
}
```

---

## Enums

### `CallState`

```dart
enum CallState {
  none, initiated, trying, ringing, answered, active, onHold, ended, error, cancel
}
```

### `SseConnectionState`

```dart
enum SseConnectionState {
  connecting, connected, disconnected, reconnecting, error
}
```
