---
title: "Create a bot"
method: POST
path: "/bots"
tags: ["Bots"]
---

# Create a bot

`POST /bots`

## Request

- Base URL: `https://www.happyscribe.com/api/v1`
- URL: `https://www.happyscribe.com/api/v1/bots`
- Auth: API key in header `Authorization`

Dispatches a notetaker bot to a Zoom, Google Meet, or Microsoft Teams call. The
bot records the call, creates a conversation, and generates a summary.

Returns `201 Created` after the bot is dispatched. It usually joins within
seconds but can take up to 3 minutes depending on availability.

A bot is one way of recording a meeting: it creates the meeting at once
(`meeting_id`), and the meeting holds the results. The recording choices
(`language`, `recording_start`, `recording_mode`, `silence_alert`,
`summary_language`, `summary_template`) are written as the meeting's own
policy; each one you leave out follows the member's and the workspace's policy.

Creation is [deduplicated](/meetingkit/send-bot#one-bot-per-meeting): a request
matching an active bot returns the existing bot instead of dispatching a
second one. When that bot was sent for another member, a request with
`member_id` answers `409 bot_already_recording`.

## Request body

- object
  - `workspace_id` string, required: Workspace that owns the bot. The API-key user must be a member. A `wks_` id; integer workspace ids are still accepted.
  - `meeting_url` string, required: Zoom, Google Meet, or Microsoft Teams join URL. URLs without a scheme are normalized to HTTPS.
  - `join_at` string, date-time: Optional future ISO 8601 timestamp with a UTC offset at which the notetaker should join. If omitted, dispatch is immediate.
  - `language` string: Optional transcription language, `auto` or `multi`. See [Languages](/api-reference/languages).
  - `participants` MeetingParticipant[]: Optional participant list of up to 100 objects.
    - `email` string: The participant's email. Used to name speakers.
    - `name` string, nullable: Resolved from the calendar invite, anything supplied at creation, the names people displayed in the call, and the people the workspace already knows, keeping the fullest. Null when no source knew one.
  - `metadata` union: Merged into the object's metadata: the keys you send are added or overwritten and the others kept. `""` as a value removes that key; `metadata: ""` removes every key. Numbers and booleans are stored as their text; objects, arrays and `null` are refused.
    - object
    - ''
  - `member_id` string: Optional member whose meeting this is, beginning with `mem_`. The meeting is theirs (their meetings list, their policy, and they are its organizer). Without it the meeting is the workspace's.
  - `bot_name` string: Display name of the notetaker in the call. Defaults to the workspace's brand kit.
  - `bot_avatar` string: Base64-encoded JPEG, with or without a `data:` URI prefix, up to 256 KB, shown as the notetaker's picture. Defaults to the workspace's brand kit. Accepted on create, never returned.
  - `welcome_message` string, nullable: Chat message posted when the notetaker joins. Send `null` to post nothing.
  - `recording_start` 'on_join' | 'on_command': When the notetaker starts recording. - `on_join`: as soon as it joins the call - `on_command`: when someone in the call asks it to
  - `recording_mode` 'audio_and_video' | 'audio_only': What the notetaker records. - `audio_and_video`: audio and video - `audio_only`: audio only
  - `silence_alert` boolean: Whether the notetaker posts an audible and chat alert after a long silence, in case it is recording nothing.
  - `summary_language` string: Language of the summary as a BCP-47 code. Defaults to the transcription language.
  - `summary_template` string: A custom summary template's `tpl_` id, or the slug of a built-in template such as `discovery_call`.

## Response `201`

The bot was dispatched.

- Bot: A bot is one way of recording a meeting. It carries its identity in the call and the meeting's recording choices; what the meeting produced (transcript, speakers, summary, media) is read from [`GET /meetings/{id}/results`](/api-reference/meetings/results).
  - `id` string: Stable typed bot ID beginning with `bot_`. Treat it as an opaque string.
  - `object` string: Always `bot`.
  - `meeting_id` string: The meeting this bot records, beginning with `mtg_`. It exists from the moment the bot is queued; read its results with `GET /meetings/{meeting_id}/results`.
  - `meeting_url` string: Normalized URL supplied at creation. Treat as sensitive — it may contain credentials.
  - `join_at` string, date-time, nullable: Requested ISO 8601 join time, or `null` for an immediate dispatch.
  - `status` 'queued' | 'joining' | 'in_call' | 'processing' | 'completed' | 'failed' | 'cancelled': Current lifecycle state: - `queued`: the provider accepted the bot and the notetaker is pending - `joining`: the notetaker is joining the call - `in_call`: the notetaker is in the call and recording - `processing`: the recording is being transcribed or summarized - `completed`: the transcript and summary are ready on the meeting - `failed`: the bot ended without a usable result - `cancelled`: the bot was cancelled
  - `bot_name` string: Display name of the notetaker in the call.
  - `welcome_message` string, nullable: Chat message the notetaker posts when it joins, or `null` when it posts none.
  - `language` string: Transcription language as a BCP-47 code, `auto` or `multi`. The meeting's `effective_policy.transcription.language`.
  - `recording_start` 'on_join' | 'on_command': When the notetaker starts recording. The meeting's `effective_policy.recording.methods.bot.start`. - `on_join`: as soon as it joins the call - `on_command`: when someone in the call asks it to
  - `recording_mode` 'audio_and_video' | 'audio_only': What the notetaker records. The meeting's `effective_policy.recording.methods.bot.mode`. - `audio_and_video`: audio and video - `audio_only`: audio only
  - `silence_alert` boolean: Whether the notetaker posts an audible and chat alert after a long silence, in case it is recording nothing. The meeting's `effective_policy.recording.methods.bot.silence_detection.alert`.
  - `summary_language` string, nullable: Language of the summary as a BCP-47 code, or `null` to follow the transcription. The meeting's `effective_policy.summary.language`.
  - `summary_template` string, nullable: The summary template that runs, a built-in slug or a custom template's `tpl_` id. The meeting's `effective_policy.summary.template`.
  - `participants` MeetingParticipant[]: Everyone invited to the meeting. Meeting rooms and the notetaker itself are excluded.
    - `email` string: The participant's email. Used to name speakers.
    - `name` string, nullable: Resolved from the calendar invite, anything supplied at creation, the names people displayed in the call, and the people the workspace already knows, keeping the fullest. Null when no source knew one.
  - `metadata` Metadata: Your own key-value pairs, for your ids and context. HappyScribe stores them, returns them on the object and in every webhook that carries it, and never acts on them. Up to 50 keys of up to 40 characters (no square brackets), values up to 500 characters. See [metadata](/meetingkit/setup#a-workspace-per-customer).
  - `created_at` string, date-time: When the bot was created.
  - `ended_at` string, date-time, nullable: When the recording first became available. `null` until then, and for a bot that never recorded. Reprocessing does not change it.
  - `reason` 'no_recording' | 'invalid_meeting_url' | 'bot_error' | 'transcription_failed': Machine-readable failure reason. Present only for failed bots. - `no_recording`: the call ended without anything recorded - `invalid_meeting_url`: the meeting URL could not be joined - `bot_error`: the notetaker failed in the call - `transcription_failed`: the recording could not be transcribed
  - `failure_message` string, nullable: Human-readable failure detail for debugging. Present only for failed bots. Do not match on its text; use `reason`.

## Other responses

- `400`: A structured input such as `participants` or `join_at` is malformed or exceeds its limit, or a recording choice has a value it does not take. Invalid `metadata` is a 422 with `field: metadata.<key>`.
- `401`: Your API key is missing (`missing_api_key`) or wrong (`invalid_api_key`), or it may not access this resource (`unauthorized`).
- `409`: A bot sent for another member is already recording this meeting. Code `bot_already_recording`; the message names that bot's id.
- `422`: The meeting URL is invalid, the provider rejected the dispatch, `member_id` is not a member of the workspace, or `summary_template` names a template this workspace cannot use. A validation error names its `field`; a template the workspace cannot use is `unusable_setting`.
- `429`: The workspace has reached the bot creation limit. Retry after the number of seconds in `Retry-After`.

---

[API](https://skmtc.dev/happyscribe/apis/happyscribe-api.md) - [All operations](https://skmtc.dev/happyscribe/apis/happyscribe-api/llms.txt) - [OpenAPI document](https://skmtc.dev/happyscribe/apis/happyscribe-api/revisions/1281bd968c3d?raw)
