> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.meetstream.ai/llms.txt.
> For full documentation content, see https://docs.meetstream.ai/llms-full.txt.

# 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&#x20;**&#x61;n&#x64;**&#x20;Microsoft Teams** via a single unified API at [api.meetstream.ai](http://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 Bot + callback_url)

Docs: https://docs.meetstream.ai/api-reference/api-endpoints/bot-endpoints/create-bot

```bash
curl -X POST "https://api.meetstream.ai/api/v1/bots/create_bot" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "meeting_link": "<YOUR_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](/api-reference/api-endpoints/bot-endpoints/get-bot-audio)
- [Video](/api-reference/api-endpoints/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=<hex_digest>`
- `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&#x20;**`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

---