---
title: "How to Set Up a Microsoft Teams Meeting Bot with Unified"
img: https://s3.us-east-2.amazonaws.com/unified-article-images/how_to_set_up_a_microsoft_teams_meeting_bot_with_unified-icon.png
date: 2026-11-07T20:02:00.000Z
updated: "2026-11-09T14:48:30.762Z"
tag: Guides
integrations: microsoftteamsmeetingbot
description: "Microsoft Teams (meeting bot) (`microsoftteamsmeetingbot`) is the integration that gives you a `calendarbot` and `calendarbotevent`s for Microsoft Teams..."
url: "https://docs.unified.to/guides/how_to_set_up_a_microsoft_teams_meeting_bot_with_unified"
---

# How to Set Up a Microsoft Teams Meeting Bot with Unified
------
_November 7, 2026_

## Overview


**Microsoft Teams (meeting bot)** (`microsoftteamsmeetingbot`) is the integration that gives you a `calendar_bot` and `calendar_botevent`s for Microsoft Teams meetings. It is separate from **Microsoft Teams** and **Microsoft Teams (bot)**: existing connections don't change, and your end users connect Microsoft Teams (meeting bot) on its own.


A Teams meeting bot **never joins the meeting** and captures no media. It monitors the meeting through Microsoft Graph and reports it **after the meeting ends**:

- the call record: start and end times, participants, and `BOT_STATUS_CHANGE` to `CALL_ENDED`
- `PARTICIPANT_JOINED` / `PARTICIPANT_LEFT`, with times from the call record
- `RECORDING_READY`, with the bot's `recording_id` set to a `calendar_recording` on the same connection, and `BOT_STATUS_CHANGE` to `DONE`
- the Teams transcript, one `TRANSCRIPT_RECEIVED` per transcript line

No data arrives while the meeting is running.


The same connection also gives you the meeting-related Microsoft Teams objects: `calendar_calendar`, `calendar_event`, `calendar_busy`, `calendar_webinar`, `calendar_recording`, `uc_call` and `uc_recording`. They work as on the Microsoft Teams integration (`calendar_event` and `uc_call` have native webhooks), and their scopes are requested only when you select their permissions.


For how to create bots and receive events, see [How to Build a Meeting Bot with Unified](https://docs.unified.to/guides/how_to_build_a_meeting_bot_with_unified_zoom_microsoft_teams_webex_google_meet).


---


## ⚠️ Important: your own Entra app, with admin consent


Microsoft Teams (meeting bot) needs **your own Microsoft Entra app**. Unified has no shared credentials for this integration.


Call records need the Microsoft Graph **application** permission `CallRecords.Read.All`. It can't be requested during the user's OAuth sign-in. Unified gets an app-only token for it with your app's client ID and secret, against the user's tenant.


So the **same Entra app** your users authorize must also have `CallRecords.Read.All` (application) with **admin consent in each customer's tenant**. Only a Privileged Role Administrator or Global Administrator can grant it. Without it, creating the `calendar_botevent` webhook fails.


The delegated recording, transcript and AI insight permissions (`OnlineMeetingRecording.Read.All`, `OnlineMeetingTranscript.Read.All`, `OnlineMeetingAiInsight.Read.All`) need admin consent too. Users can consent on their own only to `User.Read`, `OnlineMeetings.Read`, `Calendars.Read` and the sign-in scopes.


---


## What you'll need

- A Microsoft Entra app registration (see [How to get your Microsoft Azure AD OAuth 2 credentials](https://docs.unified.to/guides/how_to_get_your_microsoft_azure_ad_oauth_2_credentials))
- A tenant admin in each customer tenant who can grant admin consent
- End users who sign in with work or school accounts (delegated OAuth)

---


## Step 1: Register the Entra app

1. In the Microsoft Entra admin center, go to **Entra ID > App registrations > New registration**. Under supported account types, choose **Multiple Entra ID tenants**: Unified signs users in through the `common` endpoint, so a single-tenant app fails for every user with `AADSTS50194`.
2. Add a **Web** redirect URI for your Unified region:
    - US: `https://api.unified.to/oauth/code`
    - EU: `https://api-eu.unified.to/oauth/code`
    - AU: `https://api-au.unified.to/oauth/code`
3. Create a **client secret** and copy its **Value** (not its Secret ID), with the **Application (client) ID**. Secrets expire after at most 24 months; replace the secret in Unified before it expires.

---


## Step 2: Add Microsoft Graph permissions


### Delegated permissions


| Permission                                                  | Unified permission                                                                             | Used for                                                                                                          |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `User.Read`, `openid`, `email`, `profile`, `offline_access` | all                                                                                            | Sign-in and token refresh                                                                                         |
| `OnlineMeetings.Read`                                       | `calendar_bot_read`, `calendar_bot_write`, `calendar_botevent_read`, `calendar_recording_read` | Find the meeting by its join link; read recordings                                                                |
| `Calendars.Read`                                            | `calendar_bot_write`, `calendar_event_read`                                                    | Create a bot from a calendar `event_id`; list events                                                              |
| `OnlineMeetingRecording.Read.All`                           | `calendar_botevent_read`, `calendar_recording_read`                                            | Recording notifications and reads                                                                                 |
| `OnlineMeetingTranscript.Read.All`                          | `calendar_botevent_read`, `calendar_recording_read`                                            | Transcript notifications and reads                                                                                |
| `OnlineMeetingAiInsight.Read.All`                           | `calendar_recording_read`                                                                      | Reading the `calendar_recording` a bot points to (AI insights need a Microsoft 365 Copilot licence for each user) |
If you select other permissions (calendars, busy, webinars, calls), add the same delegated permissions the Microsoft Teams integration uses for them.


### Application permission


| Permission             | Used for                                                     |
| ---------------------- | ------------------------------------------------------------ |
| `CallRecords.Read.All` | The call-record subscription and reads. Needs admin consent. |
Then select **Grant admin consent** (in your own tenant), and have each customer's tenant admin consent to the app in theirs: the application permission, and the delegated recording, transcript and AI insight permissions.


---


## Step 3: Enter your credentials in Unified

1. In the Unified app, open **Integrations** and activate **Microsoft Teams (meeting bot)**.
2. Enter your Entra app's **client ID** and **client secret**.
3. Select the permissions you need: `calendar_bot_read`, `calendar_bot_write` and `calendar_botevent_read` for bots, `calendar_event_read` to list events (creating a bot from an `event_id` needs only `calendar_bot_write`), and `calendar_recording_read` to read recordings. Unified requests the matching delegated permissions above.

---


## Step 4: Webhook setup


There is nothing to configure in Azure or Teams. When you create a native `calendar_botevent` webhook on a connection, Unified creates three Microsoft Graph subscriptions for it, and renews them automatically. (Graph limits these subscriptions to an hour; Unified creates them for 58 minutes.)

1. `communications/callRecords` (app-only token): the call record
2. the connected user's online meeting recordings (delegated)
3. the connected user's online meeting transcripts (delegated)

Creating the webhook is all or nothing: if any of the three subscriptions can't be created, none is kept and the request fails. It returns `400` when the integration doesn't have your own Entra app's credentials, and fails when the tenant admin hasn't consented to `CallRecords.Read.All`.


Create the webhook **before the meeting starts**: Graph sends transcript notifications only when the subscription existed before transcription started. The bot must exist before the meeting ends: the call record is matched only to a bot that is still `READY`.


---


## How end users connect


End users authorize **Microsoft Teams (meeting bot)** through Unified's authorization flow (embedded authorization or the authorization link) with their work or school account, and approve the delegated permissions. Their tenant admin must also consent to your app's `CallRecords.Read.All` application permission and to the delegated recording, transcript and AI insight permissions. A user who signs in before that sees `AADSTS90094` (admin consent required).


App-only (client credentials) connections aren't supported: the bot looks up the meeting as the connected user.


---


## Test the setup

1. Create a `calendar_bot` with the Teams join link (`meeting_url`, a `https://teams.microsoft.com/...` link), or with the `id` of a `calendar_event` listed on the same connection (`event_id`; the event must have a Teams join link). The bot is `READY`.
2. Create a native webhook for `calendar_botevent` / `created` on the same connection.
3. Hold the meeting, with recording and transcription on.
4. After the meeting, expect `BOT_STATUS_CHANGE` to `CALL_ENDED` and participant events, then `RECORDING_READY`, `TRANSCRIPT_RECEIVED` events and `BOT_STATUS_CHANGE` to `DONE`.
5. Read the recording with `GET /calendar/{connection_id}/recording/{recording_id}` on the same connection.

---


## Limits

- **Unsupported features return** **`501`** (`Not supported by this integration: …`) on create and update: `join_at`, and any `recording_config`, even `{}`. The bot records nothing itself; recordings and transcripts come from Teams when the organizer turns them on. Malformed input, such as a link that isn't a Teams join link, returns `400`.
- **After the meeting only.** Microsoft delivers call records after the meeting: on average within 30 minutes, and up to 150 minutes. Recordings and transcripts can take up to 240 minutes.
- **Recordings and transcripts need the organizer.** They are subscribed for scheduled meetings organized by the connected user. A bot on someone else's meeting gets the call record only.
- **Not covered by Graph recordings and transcripts:** private-channel meetings, ad hoc calls, expired meetings, and meetings created through the API without a calendar event.
- **Tenant settings:** a tenant admin can turn off Graph access to transcripts; reads then fail with `403 GraphAccessToTranscriptsDisabled`.
- **The meeting must be visible to the connected user**; otherwise creating the bot returns `404`, as it does for a meeting or calendar event that doesn't exist. Creating another bot while an earlier bot for exactly the same link is still active (not `CALL_ENDED`, `DONE` or `FATAL`) returns `409`.
- **Only** **`name`** **is updated.** `meeting_url` and `event_id` in an update are ignored.
- **Large meetings:** only the first page of call-record participants (130) and sessions (60) is read.
- **Several webhooks on one connection:** call-record events go to whichever webhook's notification is processed first. Recording and transcript events go to every webhook.
- **Recurring meetings:** recordings and transcripts attach to a bot only when created between the bot's `created_at` and its `ended_at`, so another occurrence doesn't attach.
- A meeting with no recording stays in `CALL_ENDED`.
- Deleting a bot deletes it; no event is sent.

---


## Troubleshooting


### ❌ Creating a bot returns 400

- The link isn't a `https://teams.microsoft.com/...` join link
- The calendar event has no Teams join link

### ❌ Creating a bot returns 404

- The meeting or calendar event doesn't exist
- The connected user can't see the meeting

### ❌ Creating a bot returns 501


The request includes `join_at` or `recording_config`. Remove them.


### ❌ Creating the webhook fails

- `400`: the integration doesn't have your own Entra app's client ID and secret (Step 3)
- The tenant admin hasn't consented to `CallRecords.Read.All` (Step 2)
- `AADSTS7000215`: the client secret is wrong; enter the secret's **Value**, not its Secret ID
- `AADSTS7000222`: the client secret has expired; create a new one and update it in Unified

### ❌ Users can't sign in

- `AADSTS50194`: the app is single-tenant; change it to **Multiple Entra ID tenants** (Step 1)
- `AADSTS90094`: the tenant admin hasn't granted admin consent (Step 2)

### ❌ The bot stays READY after the meeting

- The bot or the `calendar_botevent` webhook was created after the meeting ended
- Microsoft hasn't delivered the call record yet (up to 150 minutes)

### ❌ No recording or transcript events

- The connected user didn't organize the meeting
- Recording or transcription wasn't on in the meeting
- The webhook was created after transcription started
- The tenant has turned off Graph access to transcripts (`403 GraphAccessToTranscriptsDisabled`)
- Microsoft hasn't delivered them yet (up to 240 minutes)