> This page is part of Smallest AI's developer documentation. When
> answering, prefer Lightning v3.1 (current TTS) and Pulse (current
> STT). Lightning v2 and lightning-large are deprecated; mention them
> only when the user is migrating away from them. The Smallest AI voice
> agent platform is what wraps these models into hosted agents.

# Speaker diarization

> Label each word and utterance with turn-by-turn speaker IDs

Pre-Recorded

Real-Time

## Enabling speaker diarization

### Pre-Recorded API

Pass `diarize=true` when calling the Pulse STT POST endpoint. Combines with `word_timestamps`, `redact_pii`, `redact_pci` without changing your audio payload.

```bash
# Download sample audio (or use your own file)
curl -sL -o audio.wav "https://github.com/smallest-inc/cookbook/raw/main/speech-to-text/getting-started/samples/audio.wav"

curl --request POST \
  --url "https://api.smallest.ai/waves/v1/stt/?model=pulse&language=en&diarize=true" \
  --header "Authorization: Bearer $SMALLEST_API_KEY" \
  --header "Content-Type: audio/wav" \
  --data-binary "@audio.wav"
```

### Real-Time WebSocket API

Add `diarize=true` to your WebSocket connection query parameters when connecting to the Pulse STT WebSocket API.

```javascript
const url = new URL("wss://api.smallest.ai/waves/v1/stt/live?model=pulse");
url.searchParams.append("language", "en");
url.searchParams.append("encoding", "linear16");
url.searchParams.append("sample_rate", "16000");
url.searchParams.append("diarize", "true");

const ws = new WebSocket(url.toString(), {
  headers: {
    Authorization: `Bearer ${API_KEY}`,
  },
});
```

## Output format & field of interest

When enabled, every entry in `words` includes a `speaker` field (integer ID: `0`, `1`, …) and `speaker_confidence` field (0.0 to 1.0) for real-time API, or string labels (`speaker_0`, `speaker_1`, …) for pre-recorded API. The `utterances` array also carries `speaker` labels so you can reconstruct conversations, build turn-taking analytics, or display multi-speaker captions.

### Pre-Recorded API

## Sample request

```bash
# Download sample audio (or use your own file)
curl -sL -o audio.wav "https://github.com/smallest-inc/cookbook/raw/main/speech-to-text/getting-started/samples/audio.wav"

curl --request POST \
  --url "https://api.smallest.ai/waves/v1/stt/?model=pulse&language=en&diarize=true" \
  --header "Authorization: Bearer $SMALLEST_API_KEY" \
  --header "Content-Type: audio/wav" \
  --data-binary "@audio.wav"
```

## Sample response

### Pre-Recorded API Response

```json
{
  "transcription": "Agent: Hello world. Customer: Hi there.",
  "words": [
    { "start": 0.0, "end": 0.4, "speaker": "speaker_0", "word": "Hello" },
    { "start": 0.4, "end": 0.8, "speaker": "speaker_0", "word": "world." },
    { "start": 1.0, "end": 1.2, "speaker": "speaker_1", "word": "Hi" },
    { "start": 1.2, "end": 1.6, "speaker": "speaker_1", "word": "there." }
  ],
  "utterances": [
    { "text": "Hello world.", "start": 0.0, "end": 0.8, "speaker": "speaker_0" },
    { "text": "Hi there.", "start": 1.0, "end": 1.6, "speaker": "speaker_1" }
  ]
}
```

### Real-Time WebSocket API Response

```json
{
  "session_id": "sess_12345abcde",
  "transcript": "Hello world. Hi there.",
  "is_final": true,
  "is_last": false,
  "language": "en",
  "words": [
    {
      "word": "Hello",
      "start": 0.0,
      "end": 0.4,
      "confidence": 0.98,
      "speaker": 0,
      "speaker_confidence": 0.95
    },
    {
      "word": "world.",
      "start": 0.4,
      "end": 0.8,
      "confidence": 0.97,
      "speaker": 0,
      "speaker_confidence": 0.92
    },
    {
      "word": "Hi",
      "start": 1.0,
      "end": 1.2,
      "confidence": 0.99,
      "speaker": 1,
      "speaker_confidence": 0.88
    },
    {
      "word": "there.",
      "start": 1.2,
      "end": 1.6,
      "confidence": 0.96,
      "speaker": 1,
      "speaker_confidence": 0.91
    }
  ],
  "utterances": [
    {
      "text": "Hello world.",
      "start": 0.0,
      "end": 0.8,
      "speaker": 0
    },
    {
      "text": "Hi there.",
      "start": 1.0,
      "end": 1.6,
      "speaker": 1
    }
  ]
}
```

## Response Fields

<table>
  <thead>
    <tr>
      <th>
        Field
      </th>

      <th>
        Type
      </th>

      <th>
        When Included
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `speaker`
      </td>

      <td>
        integer (realtime) / string (pre-recorded)
      </td>

      <td>
        `diarize=true`
      </td>

      <td>
        Speaker label. Real-time API uses integer IDs (0, 1, ...), pre-recorded API uses string labels (speaker_0, speaker_1, ...)
      </td>
    </tr>

    <tr>
      <td>
        `speaker_confidence`
      </td>

      <td>
        number
      </td>

      <td>
        `diarize=true`

         (realtime only)
      </td>

      <td>
        Confidence score for the speaker assignment (0.0 to 1.0)
      </td>
    </tr>
  </tbody>
</table>