> 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 AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.meetstream.ai/_mcp/server.

# Errors

> Complete MeetStream API error reference — HTTP status codes (400, 401, 403, 404, 409, 429, 500, 503, 507, 202), their meanings, real response bodies, and how to handle each.

Every MeetStream API error returns a JSON body with a single `message` field describing what went wrong:

```json
{ "message": "meeting_link is required." }
```

Branch on the **HTTP status code** first, then read `message` for the specifics. The tables below are verified against the live API.

## Status codes at a glance

| Status                      | Meaning                     | Typical cause                                                                |
| --------------------------- | --------------------------- | ---------------------------------------------------------------------------- |
| `200 OK`                    | Success                     | Request completed                                                            |
| `201 Created`               | Bot created                 | `POST /bots/create_bot` succeeded                                            |
| `202 Accepted`              | Still processing            | Data not ready yet (transcript / per-participant streams) — poll again       |
| `400 Bad Request`           | Validation error            | Missing/invalid field, unsupported provider, value out of range              |
| `401 Unauthorized`          | No API key                  | `Authorization` header missing                                               |
| `403 Forbidden`             | Invalid API key             | Key is wrong, revoked, or malformed                                          |
| `404 Not Found`             | Resource or route not found | Unknown `bot_id` / `transcript_id`, or wrong path                            |
| `409 Conflict`              | Duplicate                   | A `deduplication_key` (or re-scheduled event) already maps to a bot          |
| `429 Too Many Requests`     | Rate limited                | Slow down; honor the `Retry-After` header                                    |
| `500 Internal Server Error` | Server error                | Transient MeetStream error — retry with backoff                              |
| `503 Service Unavailable`   | Temporarily unavailable     | Overload / maintenance — retry with backoff                                  |
| `507`                       | Idempotent replay           | A retried `Idempotency-Key` replayed the original bot — **treat as success** |

The `Authorization` header is always `Token YOUR_API_KEY` (not `Bearer`). A missing header returns `401`; a present-but-invalid key returns `403`. See [Authentication](https://docs.meetstream.ai/api-reference/authentication).

## Authentication errors

| Status | Body                            | Fix                                                                                                 |
| ------ | ------------------------------- | --------------------------------------------------------------------------------------------------- |
| `401`  | `{ "message": "Unauthorized" }` | Add the header: `Authorization: Token YOUR_API_KEY`                                                 |
| `403`  | `{ "message": "Forbidden" }`    | The key is wrong/revoked — generate a new one in the [dashboard](https://app.meetstream.ai/api-key) |

## Validation errors (`400`)

Returned when the request body fails validation — **before** any bot is created, so a `400` never spawns a bot or consumes credits. The `message` names the exact problem. Common cases:

| `message`                                                                              | Cause                                                                                                                                                                                     |
| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `meeting_link is required.`                                                            | `POST /bots/create_bot` sent without `meeting_link`                                                                                                                                       |
| `in_call_recording_timeout must be at least 600 seconds`                               | `automatic_leave.in_call_recording_timeout` below 600                                                                                                                                     |
| `recording_permission_denied_timeout must not exceed 300 seconds`                      | Value above 300 (accepted range is 60–300; below 60 also `400`)                                                                                                                           |
| `live_transcription_required.webhook_url is provided but no streaming provider found…` | Set a streaming provider (`deepgram_streaming`, `assemblyai_streaming`, `jigsawstack_streaming`, `meetstream_streaming`, or `meeting_captions`) in `recording_config.transcript.provider` |
| unsupported / unconfigured provider                                                    | The transcription provider name is invalid, or its API key isn't configured on your account                                                                                               |

`400` messages are specific and actionable — always surface `message` to your logs. Fix the request and retry; a `400` is never transient.

## Not found (`404`)

The resource or route doesn't exist. Body varies by what was missing:

| Body                                    | Cause                                                           |
| --------------------------------------- | --------------------------------------------------------------- |
| `{ "message": "Bot not found" }`        | Unknown `bot_id` (also returned for a bot that was deleted)     |
| `{ "message": "Transcript not found" }` | Unknown `transcript_id`                                         |
| `{ "message": "Not Found" }`            | Unknown path, or a valid path called with an unsupported method |

## Conflict (`409`) — deduplication

When you pass a `deduplication_key` (or schedule the same calendar event twice), MeetStream returns `409` with the **existing** bot's ID rather than creating a duplicate:

```json
{
  "message": "deduplication_key already bound to a different meeting",
  "existing_bot_id": "bot_...",
  "existing_meeting_url": "https://meet.google.com/..."
}
```

To change a scheduled bot instead of colliding, use `PATCH /calendar/scheduled_bots/{bot_id}`. See [Deduplication & Idempotency Keys](https://docs.meetstream.ai/guides/features/deduplication-idempotency-keys).

## Idempotent replay (`507`)

If you retry `POST /bots/create_bot` with the **same** `Idempotency-Key`, MeetStream returns `507` with the original bot's details — **no new bot, no extra charge**. Treat `507` as success:

```python
if resp.status_code in (201, 507):
    bot = resp.json()   # same bot on 507 as on the original 201
```

By contrast, a `deduplication_key` replay returns `200` (looks like a normal create). Both are documented in the [Deduplication & Idempotency guide](https://docs.meetstream.ai/guides/features/deduplication-idempotency-keys).

## Still processing (`202`)

`202` means the request was accepted but the data isn't ready — **poll again**, don't treat it as an error.

* **Transcript not ready:** `GET /transcript/{transcript_id}/get_transcript` returns
  `{ "message": "Transcript is still being processed. Current status: <state>" }`.
* **Per-participant streams:** `get_audio_streams` / `get_recording_streams` return `{ "audio_status": "in_progress", "message": ... }` while the bot is still in the meeting.

**The `202` forever trap.** For **streaming-only** providers (`meetstream_streaming`, `*_streaming`), a post-call `get_transcript` returns `202` **indefinitely** — it never flips to a transcript. Streaming providers deliver data over the live webhook, not the post-call fetch. A blind retry loop will hang. Cap your retries and rely on the live stream as the record.

## Rate limits (`429`) and server errors (`500` / `503`)

* **`429 Too Many Requests`** — you're sending too fast. Honor the `Retry-After` response header and back off before retrying.
* **`500` / `503`** — a transient MeetStream-side error. Retry with exponential backoff. If it persists, contact [support@meetstream.ai](mailto:support@meetstream.ai).

## Operational errors (surfaced via webhooks, not HTTP)

Some failures happen *after* a successful `201` — the bot was created, then couldn't do its job. These arrive on your `callback_url`, not as an HTTP error. Webhook `status_code` is `200` for success and `500` for failure.

| Event / field                               | Meaning                                                                              | What to do                                                                                                           |
| ------------------------------------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `bot.stopped` · `bot_status: "NotAllowed"`  | Bot timed out in the waiting room / lobby                                            | Admit bots faster, raise `waiting_room_timeout`, or use a signed-in bot                                              |
| `bot.stopped` · `bot_status: "Denied"`      | Host denied the bot entry                                                            | Nothing automatic — the host must admit it                                                                           |
| `bot.stopped` · `bot_status: "Error"`       | The bot crashed mid-session                                                          | Retry with a fresh `create_bot`                                                                                      |
| `bot.error`                                 | Non-terminal streaming-provider upstream error (bot keeps running; no `status_code`) | Check your streaming provider config/keys                                                                            |
| `transcription.failed` · `status_code: 500` | Post-call transcript run failed                                                      | Read `message` (e.g. `"Deepgram API error: 401"` = provider key issue); re-run with `POST /bots/{bot_id}/transcribe` |

See [Webhooks and Events](https://docs.meetstream.ai/guides/webhooks/webhooks-and-events) for the full lifecycle and payloads.

## Handling errors well

#### Retry only what's retryable

Retry `429`, `500`, `503` (with backoff, honoring `Retry-After`). Never retry a `400` — fix the request first.

#### Make retries safe

Send an `Idempotency-Key` on `create_bot` so a network retry replays the original bot (`507`) instead of creating duplicates.

#### Don't loop on 202 forever

Cap transcript polling; streaming-only providers return `202` indefinitely by design.

#### Always log message

Every error carries a specific `message` — surface it so `400`/`404` causes are obvious.