# MeetStream Guide: Live Transcription (Streaming) via Webhook

This guide explains how to enable **live (real‑time) transcription** for a MeetStream bot using:
- `deepgram_streaming`
- `assemblyai_streaming`
You will receive streaming transcription updates on your webhook URL while the bot is in the meeting.

---

<div style="position: relative; padding-bottom: 56.25%; height: 0;"><iframe src="https://www.loom.com/embed/e688f8237ec44ad5a53208752a5b89ee" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>

---

## 1) What you need

To use live transcription you must provide:

1) A webhook endpoint that can receive POST requests (public URL).  
2) `live_transcription_required.webhook_url` in your create bot payload.  
3) A streaming provider config under `recording_config.transcript.provider`.

> Tip: For local testing, use **ngrok** or **cloudflared** to expose your local webhook to the internet.

---

## 2) Add `live_transcription_required` to your bot payload

In your Create Bot request body:

```json
"live_transcription_required": {
  "webhook_url": "{{webhook_url}}/webhook"
}
```

This is the endpoint where MeetStream will POST live transcription events.

---

## 3) Choose a streaming provider (payload examples)

### A) AssemblyAI Streaming (`assemblyai_streaming`)

```json
"live_transcription_required": {
  "webhook_url": "{{webhook_url}}/webhook"
},
"recording_config": {
  "transcript": {
    "provider": {
      "assemblyai_streaming": {
        "transcription_mode": "raw",
        "sample_rate": 48000,
        "speech_model": "universal-streaming-english",
        "format_turns": false,
        "encoding": "pcm_s16le",
        "vad_threshold": "0.4",
        "end_of_turn_confidence_threshold": "0.4",
        "inactivity_timeout": 300,
        "min_end_of_turn_silence_when_confident": "400",
        "max_turn_silence": "1280"
      }
    }
  }
}
```

---

### B) Deepgram Streaming (`deepgram_streaming`)

```json
"live_transcription_required": {
  "webhook_url": "{{webhook_url}}/webhook"
},
"recording_config": {
  "transcript": {
    "provider": {
      "deepgram_streaming": {
        "transcription_mode": "sentence",
        "model": "nova-2",
        "language": "en",
        "punctuate": true,
        "smart_format": true,
        "endpointing": 300,
        "vad_events": true,
        "utterance_end_ms": 1000,
        "encoding": "linear16",
        "channels": 1
      }
    }
  }
}
```

> Use **exactly one** provider in `recording_config.transcript.provider`.

---

## 4) What your webhook will receive (example payload)

MeetStream will POST live transcription updates to:

`{{webhook_url}}/webhook`

Example payload:

```json
{
  "bot_id": "8ceabf49-d392-4c04-8e91-bd9601a0df6e",
  "speakerName": "Madan Raj",
  "timestamp": "2026-01-24T17:00:30.354452",
  "new_text": "hear",
  "transcript": "hear",
  "utterance": "",
  "words": [
    {
      "word": "hear",
      "start": 2,
      "end": 2.08,
      "confidence": 0.999955,
      "speaker": "Madan Raj",
      "punctuated_word": "hear",
      "speech_confidence": 0.999955,
      "word_is_final": false
    }
  ],
  "end_of_turn": false,
  "turn_is_formatted": false,
  "transcription_mode": "word_level",
  "custom_attributes": {
    "tag": "Maddy",
    "sample": "testing"
  }
}
```

### Field notes (practical)
- `bot_id` — use this to map to your session/meeting.
- `speakerName` / `speaker` — speaker label (if available).
- `new_text` — incremental update (useful for streaming UI).
- `transcript` — current transcript buffer (can be partial).
- `words[]` — word-level timings + confidence.
- `word_is_final` — if `false`, treat as interim (may change).
- `end_of_turn` — can be used to “commit” a phrase/segment.
- `custom_attributes` — echoed from your Create Bot payload (useful for correlation).

---

## 5) Recommended implementation pattern

### A) Always ACK fast
Your webhook should respond **2xx quickly** (e.g., 200 OK) to avoid timeouts.

### B) Store and stream
Common approaches:
- **Live UI captions:** append `new_text` when `word_is_final=true`, or only commit when `end_of_turn=true`.
- **Analytics / downstream triggers:** run actions when `end_of_turn=true` (less noisy).
- **Persist to DB:** store word chunks with timestamps, or store turn-level segments.

### C) De-dup / idempotency
Webhooks can occasionally arrive close together. Consider de-duping with:
- `{bot_id, timestamp, new_text}` or
- a rolling hash of the payload body.

---

## 6) Troubleshooting

- No live transcription arriving?
  - Confirm `live_transcription_required.webhook_url` is reachable publicly (try `curl`).
  - Ensure your webhook endpoint path is correct (`/webhook`).
  - Confirm your webhook server accepts **POST** and returns **2xx**.

- Getting payloads but UI looks “jumpy”?
  - Treat `word_is_final=false` as interim.
  - Only commit text when `end_of_turn=true` or `word_is_final=true`.

---

