# MeetStream Guide: Webhook Events This guide explains how to receive **webhook events** from MeetStream, what each event means, and how to trigger follow-up actions like fetching **audio, video, or transcription**. Applies to: **Google Meet, Zoom, Microsoft Teams**. Support: docs.meetstream.ai • API: api.meetstream.ai --- ## 1) Add your webhook URL while creating the bot When you create a bot, include your webhook endpoint in the payload as: ```json { "callback_url": "{{webhook_url}}" } ``` MeetStream will send HTTP POST requests to your `callback_url` whenever the bot's status changes during its lifecycle and when post-call processing completes. ### Example (Create Agent + callback_url) Docs: https://docs.meetstream.ai/api-reference/api-reference/bot-endpoints/create-agent ```bash curl -X POST "https://api.meetstream.ai/api/v1/bots/create_agent" \ -H "Authorization: Token " \ -H "Content-Type: application/json" \ -d '{ "meeting_link": "", "video_required": false, "callback_url": "https://your-domain.com/webhooks/meetstream" }' ``` > Tip: Your webhook should respond quickly with **2xx** (e.g., 200) to acknowledge receipt. --- ## 2) Webhook payload format Every webhook notification follows this structure: ```json { "event": "bot.joining", "bot_id": "6667fd0c-0165-471a-a880-06a1180be377", "bot_status": "Joining", "message": "Bot is joining the meeting", "status_code": 200, "timestamp": "2026-02-27T07:11:51.863543+00:00", "custom_attributes": {} } ``` ### Fields - `event` — event type (see below) - `bot_id` — unique identifier for the bot session - `bot_status` — status detail (see **Status Reference**) - `message` — human readable explanation - `status_code` — always `200` - `timestamp` — ISO-8601 timestamp - `custom_attributes` — echoed back if you provided it when creating the bot --- ## 3) Event types (what you'll receive) MeetStream sends two categories of webhook events: **bot lifecycle events** and **post-call processing events**. ### A) Bot lifecycle events These events track the bot's presence in the meeting: | event | What it means | |---|---| | `bot.joining` | Bot started connecting to the meeting | | `bot.inmeeting` | Bot successfully joined and is actively in the meeting | | `bot.stopped` | Bot lifecycle ended (terminal event) | **Important notes:** - Every bot starts with `bot.joining`. - If the bot joins successfully, you will receive `bot.inmeeting`. - The lifecycle ends with exactly **one** `bot.stopped` event. - If the bot **fails to join** (timeout/denied/error), you may get `bot.stopped` right after `bot.joining` **without** a `bot.inmeeting`. ### B) Post-call processing events After `bot.stopped`, MeetStream continues processing the recorded session in the background. You will receive additional webhook events as each artifact finishes processing: | event | What it means | |---|---| | `audio.processed` | Audio extraction and processing completed | | `transcription.processed` | Transcription generation completed | | `video.processed` | Video processing completed | | `data_deletion` | Bot data has been deleted (via retention policy or manual request) | These events arrive **asynchronously** after the bot has stopped — the order and timing depend on processing duration for each artifact. #### Example payloads **`audio.processed`** ```json { "bot_id": "5b0ff6e7-3cea-4c9f-a6b4-851c5f11cf4f", "event": "audio.processed", "audio_status": "Success", "message": "Audio processing completed successfully", "status_code": 200 } ``` **`transcription.processed`** ```json { "bot_id": "5b0ff6e7-3cea-4c9f-a6b4-851c5f11cf4f", "event": "transcription.processed", "transcript_status": "Success", "message": "Transcript processing completed successfully", "status_code": 200 } ``` **`video.processed`** ```json { "bot_id": "5b0ff6e7-3cea-4c9f-a6b4-851c5f11cf4f", "event": "video.processed", "video_status": "Success", "message": "Video processing completed successfully", "status_code": 200 } ``` **`data_deletion`** ```json { "bot_id": "5b0ff6e7-3cea-4c9f-a6b4-851c5f11cf4f", "event": "data_deletion", "status": "success", "message": "Bot data deleted successfully", "deleted_objects": 5, "timestamp": "2024-01-15T14:30:00Z", "status_code": 200 } ``` --- ## 4) Status reference (bot_status) `bot_status` gives more detail, especially for `bot.stopped`. | bot_status | event | Meaning | |---|---|---| | `Joining` | `bot.joining` | Bot is connecting | | `InMeeting` | `bot.inmeeting` | Bot is in the meeting and recording | | `Stopped` | `bot.stopped` | Bot exited normally (meeting ended, removed via API, everyone left, voice timeout, removed by host, etc.) | | `NotAllowed` | `bot.stopped` | Bot could not join (commonly waiting room/lobby timeout) | | `Denied` | `bot.stopped` | Host explicitly denied join or recording permission | | `Error` | `bot.stopped` | Unexpected error during lifecycle | --- ## 5) Recommended actions based on webhook events Your server can react to webhook events and run follow-up workflows. ### A) On `bot.inmeeting` Typical actions: - Update your UI/state: "bot is live" - Start timers / internal tracking - Notify other systems that recording has started ### B) On `bot.stopped` (terminal) This is the moment to mark the session as complete. Artifacts may still be processing at this point. Recommended flow: 1. Receive `bot.stopped` 2. Read `bot_status` 3. If `bot_status` is `Stopped` (normal exit), wait for processing events before fetching outputs. 4. If `bot_status` is `NotAllowed` / `Denied` / `Error`, log the reason (`message`) and alert/handle accordingly. ### C) On post-call processing events Once you receive `audio.processed`, `transcription.processed`, or `video.processed`, the corresponding artifact is ready to fetch: - Audio: https://docs.meetstream.ai/api-reference/api-reference/bot-endpoints/get-bot-audio - Video: https://docs.meetstream.ai/api-reference/api-reference/bot-endpoints/get-bot-video ### D) On `data_deletion` Confirms that bot data has been removed. Update your records accordingly — further fetch requests for this bot's artifacts will fail. --- ## 6) Webhook signing (optional but recommended) If you configure a webhook secret, MeetStream includes an HMAC signature in headers: - `X-MeetStream-Signature`: `sha256=` - `X-MeetStream-Timestamp`: ISO 8601 timestamp Verification steps: 1. Compute `HMAC-SHA256(your_secret, raw_request_body)` 2. Compare with `X-MeetStream-Signature` (strip `sha256=` prefix) 3. Optionally validate timestamp is within an acceptable window (replay protection) --- ## 7) Retry behavior (important) - Webhook delivery is **best-effort**. - If your endpoint returns a **non-2xx**, the webhook is **not retried**. - A bot may send up to **3 `bot.joining`** events if join retries are configured. - `bot.inmeeting` and `bot.stopped` are sent **at most once**. - Post-call processing events (`audio.processed`, `transcription.processed`, `video.processed`, `data_deletion`) are sent **at most once**. --- ## 8) Minimal webhook handler checklist - ✅ Accept `POST` requests at `callback_url` - ✅ Verify signature (if enabled) - ✅ Always respond **2xx quickly** - ✅ Idempotent handling (store processed event IDs or de-dupe by `{bot_id, event, timestamp}`) - ✅ On `bot.stopped`, mark session complete - ✅ On `audio.processed` / `video.processed` / `transcription.processed`, fetch the corresponding artifact - ✅ On `data_deletion`, clean up local references --- If you want, share your preferred stack (Node/FastAPI/Cloudflare Workers), and I'll provide a ready-to-paste webhook handler example.