Skip to navigation

Live Meeting Transcription via Webhook

View as Markdown

Get transcript updates on your webhook while the meeting is still going, a second or two after people speak.

You choose a streaming provider and a webhook URL; the bot sends the meeting audio to the provider and POSTs each result to your webhook.



Platform support

ZoomGoogle MeetMicrosoft Teams
deepgram_streamingYesYesYes
assemblyai_streamingYesYesYes
sarvam_streamingYesYesYes
meetstream_streaming (no provider key)YesYesYes
jigsawstack_streamingNo (accepted, but no transcript is sent)YesNo (accepted, but no transcript is sent)
Native captions live (meeting_captions)NoYes, see meeting captionsNo (saved after the call instead)
Speaker labels (speakerName, speakerId)Exact: each speaker’s audio is transcribed on its ownThe active speaker when the phrase was spokenThe dominant speaker when the phrase was spoken

One streaming provider runs per bot. If you list several, only one is used, so list only the one you want. The rest of the platform matrix is on Meeting Platforms Supported.


1) What you need

  1. A webhook endpoint that accepts POST requests on a public https:// URL.
  2. live_transcription_required.webhook_url in your Create Bot request.
  3. One streaming provider under recording_config.transcript.provider.
  4. For Deepgram, AssemblyAI, Sarvam or JigsawStack: your provider key saved under Integrations > Transcription in the dashboard (details). meetstream_streaming needs no key.

You can build the same request in the dashboard’s API Playground, on the Transcribe step:

API Playground bot builder on the Transcribe step with Live transcription selected, and the streaming provider and webhook URL fields highlighted
API Playground, Transcribe step: (1) Live transcription, (2) the streaming provider, (3) live_transcription_required.webhook_url. The form marks the webhook as optional, but the API requires it for every streaming provider.

The two go together: a streaming provider without webhook_url is rejected with 400 (live_transcription_required.webhook_url is mandatory when using streaming providers: ...), and a webhook_url without a streaming provider (or meeting_captions) is rejected too.

Tip: For local testing, expose your server with a tunnel. See set up a local server for webhooks.


2) Add live_transcription_required to your bot payload

"live_transcription_required": {
"webhook_url": "https://example.com/webhook"
}

This is where MeetStream will POST live transcript updates.


3) Choose a streaming provider (payload examples)

A) AssemblyAI Streaming (assemblyai_streaming)

"live_transcription_required": {
"webhook_url": "https://example.com/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)

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

Set model explicitly: the default differs by platform.


C) MeetStream-hosted (meetstream_streaming)

"live_transcription_required": {
"webhook_url": "https://example.com/webhook"
},
"recording_config": {
"transcript": {
"provider": {
"meetstream_streaming": { "transcription_mode": "sentence" }
}
}
}

No provider key needed.


transcription_mode

ModeWhat each POST containsUse it for
raw (default)Everything the provider returns, including interim results (is_final: false)Full control, custom UIs
word_levelOnly the newly recognized words since the last POST, in transcriptLive captions, typing effect
sentenceOne finished phrase per POST, in utteranceNotes, triggers, storage

Any other value is rejected with 400 (Invalid transcription_mode: ...).

Only one streaming provider runs per bot. You can add a post-call provider in the same request if you also want a clean transcript after the meeting. See transcription providers.


4) What your webhook will receive

Every POST has Content-Type: application/json. Common fields:

FieldMeaning
bot_idThe bot, to map to your meeting
speakerName, speakerIdWho spoke. See the speaker labels row in platform support
timestampWhen the result was produced
transcriptThe text for this POST (for sentence, the same as utterance)
transcription_moderaw, word_level or sentence
custom_attributesEchoed from your Create Bot request, when you set it

sentence mode

{
"bot_id": "8ceabf49-d392-4c04-8e91-bd9601a0df6e",
"speakerName": "Jane Smith",
"speakerId": "16778240",
"timestamp": "2026-09-20T17:00:30.354452",
"utterance": "Can everyone hear me?",
"transcript": "Can everyone hear me?",
"words": [
{ "word": "can", "start": 2.0, "end": 2.08, "confidence": 0.99, "punctuated_word": "Can" }
],
"end_of_turn": true,
"turn_is_formatted": false,
"turn_order": 4,
"end_of_turn_confidence": null,
"transcription_mode": "sentence",
"custom_attributes": { "crm_id": "88421" }
}

word_level mode

{
"bot_id": "8ceabf49-d392-4c04-8e91-bd9601a0df6e",
"speakerName": "Jane Smith",
"speakerId": "16778240",
"timestamp": "2026-09-20T17:00:30.354452",
"transcript": "hear",
"utterance": "",
"transcription_mode": "word_level"
}

raw mode

raw adds the provider’s own fields: words, utterance, is_final (Deepgram), and end_of_turn, turn_is_formatted, turn_order, end_of_turn_confidence (AssemblyAI). Interim results arrive with is_final: false and are replaced by later POSTs.

words[] entries come from the provider, so their exact keys depend on which provider you chose.


A) Always ACK fast

Respond 2xx immediately and do the work asynchronously. Live transcript POSTs are sent once: they are not retried, and a slow endpoint can make you miss updates.

B) Protect the endpoint

Live transcript POSTs are not signed (unlike the lifecycle webhooks). Use a hard-to-guess URL path, check that bot_id is one of your bots, and ignore anything else.

C) Store and stream

  • Live UI captions: use word_level, or raw and show interim text until is_final / end_of_turn.
  • Analytics and triggers: use sentence; each POST is a finished phrase.
  • Persist to a database: store sentence POSTs, or raw POSTs where is_final is true.

D) De-duplicate

Updates can arrive close together. De-duplicate on {bot_id, timestamp, transcript} or a hash of the body.

E) Pausing

While recording is paused, no transcript is produced, because the provider receives silence (or nothing).


6) Troubleshooting

  • No live transcription arriving?

    • Check the bot got into the meeting: transcription starts after admission. See bot status and error codes.
    • Confirm live_transcription_required.webhook_url is reachable publicly (try curl -X POST) and returns 2xx.
    • On Zoom and Teams, jigsawstack_streaming produces nothing. Use another streaming provider.
    • Check your provider key is saved and valid. When the provider rejects the connection, a bot.error event is sent to your webhooks with the reason.
  • Payloads arrive but the UI looks jumpy?

    • In raw mode, treat is_final: false as interim and replace it with the next update.
    • Or switch to sentence mode.
  • Speaker names look wrong on Google Meet or Teams?

    • Live labels there follow the active or dominant speaker, so quick back-and-forth or crosstalk can be attributed to the wrong person. Add a post-call provider to the same request for a final transcript with speaker labels from the recording.