Skip to navigation

Errors

How the MeetStream API reports errors, every status code, what causes it, and how to fix it.
View as Markdown

MeetStream reports problems in two places: an HTTP error when a request is rejected, and a bot status or webhook when a bot that was created successfully cannot do its job. This page covers HTTP errors. For bot-level statuses, ErrorReason codes and messages on Zoom, Google Meet and Microsoft Teams, see the Bot status and error code reference.

Most errors return a JSON body with a message field:

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

A few endpoints return error instead, with extra fields: in-meeting commands (send message, send image, pause, resume), the credit check on create_bot, and signed-in login management. Read both keys:

body = resp.json()
reason = body.get("message") or body.get("error")

Branch on the HTTP status code first, then log the text for the specifics.

Status codes at a glance

StatusMeaningTypical cause
200 OKSuccessRequest completed
201 CreatedBot createdPOST /bots/create_bot succeeded
202 AcceptedStill processing, or command acceptedData not ready yet (transcript, per-participant streams); poll again
400 Bad RequestValidation errorMissing or invalid field, unsupported meeting link, unsupported provider, value out of range
403 ForbiddenNot allowedMissing or invalid API key, another account’s bot, or not enough credits
404 Not FoundResource or route not foundUnknown bot_id or transcript_id, or wrong path
409 ConflictConflicts with current stateDeduplication conflict, bot not in the meeting yet, or a signed-in login is busy
429 Too Many RequestsRate or capacity limitIn-meeting command rate limit, or no signed-in login available
500 Internal Server ErrorServer errorTransient MeetStream error; retry with backoff
503 Service UnavailableTemporarily unavailableA dependency is not ready; retry with backoff
507Idempotent replayA retried Idempotency-Key replayed the original bot; treat as success

The Authorization header is always Token YOUR_API_KEY (not Bearer). A missing header, a malformed header and an invalid or revoked key all return 403 with { "message": "Forbidden" }. See Authentication.

Authentication and access errors (403)

BodyCauseFix
{ "message": "Forbidden" }The Authorization header is missing, uses Bearer, or the key is wrong or revoked.Send Authorization: Token YOUR_API_KEY. Create a key in the dashboard.
{ "message": "Unauthorized bot access attempt" } or { "error": "Forbidden" }The bot_id belongs to another account or workspace.Use a key from the workspace that created the bot.
{ "error": "Low credits please recharge", "available_credits": ..., "minimum_required": ... }create_bot on a pay-as-you-go account with less than 30 minutes of credit.Add credits in Billing.
{ "error": "Low credits please recharge", "active_bots": 1 }Balance under $1 while another bot is running.Add credits, or wait for the running bot to finish.

Treat any 401 Unauthorized you receive the same way as 403: check the key and header. Very high request rates from one IP address can also be blocked with 403.

Validation errors (400)

Returned when the request 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:

messageCause
meeting_link is required.POST /bots/create_bot sent without meeting_link
meeting_link host '...' is not a supported meeting platform. Expected Google Meet (meet.google.com), ...The link is not a Zoom, Google Meet, Microsoft Teams or WhatsApp call link
meeting_link looks like the GMeet site root or a marketing page, not a meeting URL: '...'The link is a site root or a page such as /signin instead of a meeting
Zoom bots require a connected Zoom app or Zoom credentials in the user profileNo Zoom Meeting SDK credentials configured; see Zoom setup
waiting_room_timeout for GMeet must not exceed 600 seconds (got 900)An automatic_leave value is outside the per-platform range
in_call_recording_timeout must be at least 600 seconds (got 300)automatic_leave.in_call_recording_timeout below 600
recording_permission_denied_timeout must not exceed 300 seconds (got 400)Value above 300 (accepted range is 60 to 300)
live_transcription_required.webhook_url is provided but no streaming provider found...Set a live provider in recording_config.transcript.provider, such as deepgram_streaming or assemblyai_streaming, or meeting_captions. See live transcription
join_at must be in the futureScheduled time is in the past
Invalid join_at format: Cannot schedule bot more than 90 days (3 months) in the future. ...join_at is more than 90 days ahead
unsupported or unconfigured providerThe transcription provider name is invalid, or its API key isn’t configured on your account

Platform-specific 400s (Zoom token URLs, Google and Teams signed-in domains, teams.live.com sign-in) are listed in HTTP errors from create_bot.

400 messages are specific and actionable. Always log them. 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:

BodyCause
{ "message": "Bot not found" }Unknown bot_id (also returned for a scheduled 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)

BodyCauseFix
{ "message": "deduplication_key already bound to a different meeting", "existing_bot_id": ..., "existing_meeting_url": ... }A deduplication_key was reused for a different meeting link. Replaying it with the same link returns 200 and the existing bot.Use a new key for a new meeting. See Deduplication & Idempotency Keys.
A bot is already scheduled for this eventA calendar event already has a scheduled bot.Change it with PATCH /calendar/scheduled_bots/{bot_id} instead.
{ "error": "Bot is not currently in a meeting.", "bot_status": ..., "detail": ... }An in-meeting command was sent while the bot was still in the lobby or had already left.Wait for bot.inmeeting before sending commands.
teams.sign_in_email '...' is currently in useA pinned Teams login is serving another bot.Retry later, or set strict_email: false.

Rate and capacity limits (429)

BodyCauseFix
{ "error": "Rate limit exceeded", "limit": 30, ... }More than 30 in-meeting commands per minute for one bot (5 per minute for screenshots). The response includes a Retry-After header.Wait for Retry-After seconds, then retry.
All Teams logins under domain '...' are currently in useEvery Teams signed-in login is serving a bot.Add logins or retry later. See Teams signed-in bots.
All N active logins under domain '...' are at capacity (30 active sessions each)Every Google signed-in login is at capacity.Add logins or retry later. See Google signed-in bots.

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:

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.

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 live-only providers (*_streaming), a post-call get_transcript returns 202 indefinitely; it never flips to a transcript. Live providers deliver text over your 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.

Server errors (500 / 503)

A transient MeetStream-side error. Retry with exponential backoff. If it persists, contact support@meetstream.ai with the request time and any bot_id.

Operational errors (surfaced via bot status and webhooks, not HTTP)

Some failures happen after a successful 201: the bot was created, then couldn’t join or had to leave. These arrive as a terminal webhook on your callback_url or workspace endpoints, and in the bot’s status. Every ending uses event: "bot.stopped"; the reason is in bot_event.

bot_event · bot_statusMeaningWhat to do
bot.notallowed · NotAllowedNobody admitted the bot before waiting_room_timeoutAdmit bots faster, raise waiting_room_timeout, or use a signed-in bot for Google Meet or Microsoft Teams
bot.denied · DeniedThe host denied the bot entryNothing automatic; the host must admit it
bot.failed · FailedThe meeting blocked the join (invalid link, restricted, not started, ended, sign-in required)Read ErrorReason in /detail and follow the reference
bot.failed · ErrorCredentials, token, link format, sign-in or a MeetStream-side problemRead the message and follow the reference
bot.errorA live transcription provider failed while the bot kept running, or a scheduled bot was rejected when it tried to startCheck your provider keys, or read the message and schedule a new bot
transcription.failed · status_code: 500Post-call transcript run failedRead message (for example "Deepgram API error: 401" means a provider key issue); re-run with POST /bots/{bot_id}/transcribe

Handling errors well

Retry only what's retryable

Retry 429, 500, 503 with backoff, honoring Retry-After when present. 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; live-only providers return 202 indefinitely by design.

Always log the text

Every error carries a specific message or error; surface it so 400 and 404 causes are obvious.