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

# MeetStream Guide: Outlook Calendar Integration & Auto-Scheduling

This guide explains how to connect your Microsoft Outlook / Microsoft 365 Calendar to MeetStream so bots can automatically join your meetings — no manual API calls required.

Applies to: **Google Meet, Zoom, Microsoft Teams** meetings on your Outlook Calendar.
Support: docs.meetstream.ai | API: api.meetstream.ai

---

## What you get with Calendar Integration

Once connected, MeetStream can:

- **See your upcoming meetings** — synced directly from Outlook Calendar via Microsoft Graph API with delta sync for speed
- **Schedule bots for specific meetings** — one click or one API call
- **Auto-schedule bots for all meetings** — hands-free, every day
- **Handle recurring meetings** — automatically reschedule bots for the next occurrence
- **React to calendar changes in real time** — if a meeting is rescheduled, the bot's join time updates automatically; if a meeting is cancelled, the bot is cancelled too
- **Manage scheduled bots** — list, update, or delete scheduled bots at any time
- **Keep subscriptions alive** — Microsoft Graph change notification subscriptions are automatically renewed before they expire

---

## 1) Get your Microsoft OAuth credentials

Before connecting your calendar, you need three things from Microsoft: a **Client ID**, **Client Secret**, and **Refresh Token**. Follow these steps to get them.

### Step 1: Register an app in Azure Portal

1. Go to the [Azure Portal](https://portal.azure.com/).
2. Navigate to **Azure Active Directory > App registrations**.
3. Click **New registration**.
4. Give your app a name (e.g. "MeetStream Calendar").
5. Under **Supported account types**, select **Accounts in any organizational directory and personal Microsoft accounts**.
6. Under **Redirect URI**, select **Web** and enter:
   ```
   http://localhost:3000/api/microsoft/oauth-callback
   ```
7. Click **Register**.
8. On the app overview page, copy your **Application (client) ID** — this is your **Client ID**.

### Step 2: Create a client secret

1. In your app registration, go to **Certificates & secrets**.
2. Click **New client secret**.
3. Give it a description and choose an expiry period.
4. Click **Add** and immediately copy the **Value** — this is your **Client Secret**. It won't be shown again.

### Step 3: Add Microsoft Graph API permissions

1. In your app registration, go to **API permissions**.
2. Click **Add a permission > Microsoft Graph > Delegated permissions**.
3. Add the following permissions:

| Permission | Purpose |
|---|---|
| `Calendars.Read` | Read calendar events |
| `User.Read` | Read user profile and email |
| `offline_access` | Obtain refresh tokens for long-lived access |

4. Click **Grant admin consent** if you have admin rights, or ask your tenant admin to grant consent.

### Step 4: Run the OAuth helper to get your refresh token

MeetStream provides a lightweight Node.js helper that runs the OAuth consent flow locally and returns your refresh token.

**Prerequisites:** Node.js installed on your machine.

1. Create a `.env` file in the project root with your credentials:

```
MICROSOFT_CLIENT_ID=<YOUR_CLIENT_ID>
MICROSOFT_CLIENT_SECRET=<YOUR_CLIENT_SECRET>
```

2. Install dependencies and start the helper server:

```bash
npm install express @azure/msal-node dotenv
node server_microsoft.js
```

You'll see:

```
Open http://localhost:3000 to start the OAuth flow
Redirect URI: http://localhost:3000/api/microsoft/oauth-callback

Make sure this redirect URI is added in Azure Portal → App registrations → Authentication → Redirect URIs
```

3. Open **http://localhost:3000** in your browser.
4. Sign in with your Microsoft account and grant calendar access.
5. After authorization, the page displays your **Refresh Token** and **Access Token**.
6. Copy the **Refresh Token** — you'll need it in the next step.

> If the refresh token is not returned, make sure `offline_access` is included in your permissions and that you clicked **Accept** on the consent screen. Microsoft only returns a refresh token when `offline_access` is in the requested scope.

### Required scopes

The helper requests these scopes:

| Scope | Purpose |
|---|---|
| `Calendars.Read` | Read calendar events and calendar list |
| `User.Read` | Identify the Microsoft account and profile |
| `offline_access` | Obtain long-lived refresh tokens |

You now have everything you need: **Client ID**, **Client Secret**, and **Refresh Token**.

---

## 2) Connect your Outlook Calendar

With your credentials ready, connect your Outlook Calendar to MeetStream.

### API endpoint

```
POST https://api.meetstream.ai/api/v1/calendar/create_calendar
```

### Request body

```json
{
  "microsoft_client_id": "<YOUR_MICROSOFT_CLIENT_ID>",
  "microsoft_client_secret": "<YOUR_MICROSOFT_CLIENT_SECRET>",
  "microsoft_refresh_token": "<YOUR_MICROSOFT_REFRESH_TOKEN>"
}
```

### What happens behind the scenes

1. MeetStream validates your credentials by refreshing the access token with Microsoft.
2. Fetches all your calendars (default, secondary, shared) via Microsoft Graph.
3. Stores your credentials securely (encrypted at rest in AWS SSM Parameter Store).
4. Sets up **Microsoft Graph change notification subscriptions** on your calendars — so MeetStream is notified in real time when events are created, updated, or cancelled.
5. Fetches your Microsoft profile info (email, display name) for display purposes.

### Example cURL

```bash
curl -X POST "https://api.meetstream.ai/api/v1/calendar/create_calendar" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "microsoft_client_id": "<YOUR_MICROSOFT_CLIENT_ID>",
    "microsoft_client_secret": "<YOUR_MICROSOFT_CLIENT_SECRET>",
    "microsoft_refresh_token": "<YOUR_MICROSOFT_REFRESH_TOKEN>"
  }'
```

### Response

```json
{
  "calendar_id": "outlook_calendar_usr_abc123",
  "platform": "outlook_calendar",
  "user_email": "user@example.com",
  "user_name": "Jane Smith",
  "calendars": [
    {
      "id": "AQMkADAwATM0MDAA...",
      "summary": "Calendar",
      "isPrimary": true,
      "accessRole": "owner",
      "selected": true
    },
    {
      "id": "AQMkADAwATM0MDAB...",
      "summary": "Team Meetings",
      "isPrimary": false,
      "accessRole": "writer",
      "selected": true
    }
  ],
  "primary_calendar_id": "AQMkADAwATM0MDAA...",
  "watch_setup": {
    "success": true,
    "subscriptions_setup": 2,
    "subscription_results": [
      {
        "calendar_id": "AQMkADAwATM0MDAA...",
        "calendar_summary": "Calendar",
        "subscription_id": "a1b2c3d4-...",
        "expiration": "2026-05-23T22:00:00Z"
      }
    ],
    "failed_calendars": []
  },
  "message": "Calendar connected successfully"
}
```

> **Note:** If you call this endpoint again with updated credentials, MeetStream replaces the existing connection — no need to disconnect first.

---

## 3) View your calendars

After connecting, you can list all calendars linked to your Microsoft account.

### API endpoint

```
GET https://api.meetstream.ai/api/v1/calendar/calendars
```

### Example cURL

```bash
curl -X GET "https://api.meetstream.ai/api/v1/calendar/calendars" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

### Response

```json
{
  "calendars": [
    {
      "id": "AQMkADAwATM0MDAA...",
      "summary": "Calendar",
      "isPrimary": true,
      "accessRole": "owner",
      "timeZone": "America/New_York",
      "backgroundColor": "#0078d4",
      "selected": true
    }
  ],
  "total": 1,
  "user_id": "usr_abc123"
}
```

> This is a live call to the Microsoft Graph API and always returns the latest calendar list.

---

## 4) Sync and view your events

MeetStream syncs events from Outlook Calendar and stores them locally. It detects meeting links for supported platforms (Google Meet, Zoom, Microsoft Teams, Webex, GoToMeeting, BlueJeans, and Whereby).

### Sync events from Outlook Calendar

```
GET https://api.meetstream.ai/api/v1/calendar/events
```

This is the primary events endpoint. It syncs with Outlook Calendar (using Microsoft Graph delta sync for speed), stores events in MeetStream's database, and returns them with pagination and linked bot information.

#### Query parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `calendar_id` | string | primary calendar | Specific calendar to sync |
| `time_min` | ISO 8601 | now - 1 day | Start of the time window |
| `time_max` | ISO 8601 | now + 28 days | End of the time window |
| `sync` | `"true"` / `"false"` | auto | Force a sync from Outlook Calendar |
| `limit` | int (1-100) | 50 | Number of events per page |
| `cursor` | string | — | Pagination cursor from `next` field |
| `cleanup_duplicates` | `"true"` / `"false"` | `"false"` | Deduplicate events |

#### Example cURL

```bash
curl -X GET "https://api.meetstream.ai/api/v1/calendar/events?limit=20" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

#### Response

```json
{
  "next": "eyJFdmVudElEIjogIm...",
  "previous": null,
  "results": [
    {
      "id": "evt_abc123",
      "start_time": "2026-04-08T15:00:00Z",
      "end_time": "2026-04-08T16:00:00Z",
      "calendar_id": "AQMkADAwATM0MDAA...",
      "platform": "outlook_calendar",
      "platform_id": "outlook_evt_456",
      "ical_uid": "abc123@outlook.com",
      "meeting_platform": "Teams",
      "meeting_url": "https://teams.microsoft.com/l/meetup-join/...",
      "is_deleted": false,
      "created_at": "2026-04-01T12:00:00Z",
      "updated_at": "2026-04-07T09:30:00Z",
      "raw": { },
      "bots": [
        {
          "id": "bot_111",
          "status": "Scheduled",
          "scheduled_join_time": "2026-04-08T14:59:00+00:00",
          "bot_username": "MeetStream Calendar Bot",
          "platform": "Teams",
          "is_scheduled": true
        }
      ]
    }
  ],
  "has_more": false
}
```

Use the `next` cursor value in a subsequent request to fetch the next page:

```bash
curl -X GET "https://api.meetstream.ai/api/v1/calendar/events?cursor=eyJFdmVudElEIjogIm..." \
  -H "Authorization: Token <YOUR_API_KEY>"
```

### Get events from local database only

```
GET https://api.meetstream.ai/api/v1/calendar/get_events
```

This is a lightweight endpoint that returns events already synced to MeetStream without calling the Microsoft Graph API. Useful when you want fast reads and don't need the latest sync.

```bash
curl -X GET "https://api.meetstream.ai/api/v1/calendar/get_events" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

---

## 5) Schedule a bot for a specific meeting

Pick a meeting from your synced events and schedule a bot for it.

### API endpoint

```
POST https://api.meetstream.ai/api/v1/calendar/schedule/{event_id}
```

### Path parameters

| Parameter | Description |
|---|---|
| `event_id` | MeetStream event ID (the `id` field from the events list) |

### Request body

```json
{
  "bot_config": {
    "bot_name": "My Meeting Bot",
    "audio_required": true,
    "video_required": false,
    "bot_message": "Bot joining to record this meeting",
    "callback_url": "https://your-domain.com/webhooks/meetstream",
    "transcription": {
      "deepgram": { "model": "nova-3", "language": "en" }
    },
    "automatic_leave": {
      "no_one_joined_timeout": 300,
      "everyone_left_timeout": 60
    },
    "recording_config": {
      "video_recording": false
    }
  }
}
```

The `bot_config` accepts the same fields you'd normally pass to the Create Bot API.

### Example cURL

```bash
curl -X POST "https://api.meetstream.ai/api/v1/calendar/schedule/evt_abc123" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "bot_config": {
      "video_required": false,
      "callback_url": "https://your-domain.com/webhooks/meetstream"
    }
  }'
```

### Response

```json
{
  "scheduled": true,
  "schedule_id": "bot-usr_abc1-bot_111aaa12",
  "bot_id": "bot_111...",
  "schedule_group": "teams",
  "event_id": "evt_abc123",
  "scheduled_time": "2026-04-08T14:59:00Z",
  "bot_config": { },
  "is_recurring_occurrence": false
}
```

### Scheduling options for recurring events

| Body field | Type | Default | Description |
|---|---|---|---|
| `occurrence_date` | ISO 8601 | — | Schedule a bot for a specific occurrence of a recurring event |
| `schedule_all_occurrences` | bool | `false` | Schedule bots for all future occurrences at once |
| `occurrence_limit` | int | 52 | Maximum number of occurrences to schedule when using `schedule_all_occurrences` |
| `recurring_event` | bool | `false` | Enable auto-rescheduling — after the bot joins this occurrence, automatically schedule the next one |

### Deduplication

If you schedule a bot for the same event twice, MeetStream returns a `409 Conflict` with the existing bot's ID. To update the bot config, use `PATCH /calendar/scheduled_bots/{bot_id}` instead.

---

## 6) Unschedule a bot

Cancel a scheduled bot for a specific event.

### API endpoint

```
DELETE https://api.meetstream.ai/api/v1/calendar/schedule/{event_id}
```

### Request body (optional)

```json
{
  "cancel_all_occurrences": false,
  "from_date": "2026-05-01T00:00:00Z"
}
```

| Body field | Type | Default | Description |
|---|---|---|---|
| `cancel_all_occurrences` | bool | `false` | Cancel bots for all occurrences of a recurring series |
| `from_date` | ISO 8601 | — | Only cancel occurrences from this date forward |

### Example cURL

```bash
curl -X DELETE "https://api.meetstream.ai/api/v1/calendar/schedule/evt_abc123" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

### Response

```json
{
  "unscheduled": true,
  "event_id": "evt_abc123",
  "cancelled_schedules": ["bot-usr_abc1-bot_111aaa12"],
  "schedules_cancelled": 1,
  "bots_deleted": 1,
  "cancel_all_occurrences": false,
  "is_recurring_series": false
}
```

---

## 7) Manage scheduled bots

View, update, or delete your scheduled bots across all events.

### List all scheduled bots

```
GET https://api.meetstream.ai/api/v1/calendar/scheduled_bots
```

Returns all bots with a scheduled join time in the future.

#### Query parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `limit` | int (1-100) | 100 | Maximum number of bots to return |

#### Example cURL

```bash
curl -X GET "https://api.meetstream.ai/api/v1/calendar/scheduled_bots" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

#### Response

```json
{
  "scheduled_bots": [
    {
      "bot_id": "bot_111...",
      "platform": "Teams",
      "status": "Scheduled",
      "scheduled_join_time": "2026-04-08T14:59:00+00:00",
      "bot_username": "MeetStream Calendar Bot",
      "meeting_link": "https://teams.microsoft.com/l/meetup-join/...",
      "custom_attributes": {
        "source": "calendar_integration",
        "event_id": "outlook_evt_456",
        "event_summary": "Weekly Standup"
      },
      "is_scheduled": true,
      "created_at": "2026-04-07T10:00:00Z"
    }
  ]
}
```

### Update a scheduled bot

```
PATCH https://api.meetstream.ai/api/v1/calendar/scheduled_bots/{bot_id}
```

Update the join time, display name, or other properties of a scheduled bot.

#### Request body

All fields are optional — include only what you want to change.

```json
{
  "scheduled_join_time": "2026-04-08T16:59:00Z",
  "bot_username": "Updated Bot Name",
  "custom_attributes": { "note": "VIP meeting" }
}
```

| Body field | Type | Description |
|---|---|---|
| `scheduled_join_time` | ISO 8601 | New join time (must be in the future). Updates the EventBridge schedule too. |
| `bot_username` | string | Display name for the bot in the meeting |
| `custom_attributes` | object | Custom metadata attached to the bot |

#### Response

```json
{
  "message": "Scheduled bot updated successfully",
  "bot_id": "bot_111...",
  "updated_fields": ["scheduled_join_time", "bot_username"],
  "schedule_updated": true
}
```

### Delete a specific scheduled bot

```
DELETE https://api.meetstream.ai/api/v1/calendar/scheduled_bots/{bot_id}
```

```bash
curl -X DELETE "https://api.meetstream.ai/api/v1/calendar/scheduled_bots/bot_111..." \
  -H "Authorization: Token <YOUR_API_KEY>"
```

```json
{
  "message": "Scheduled bot deleted successfully",
  "bot_id": "bot_111..."
}
```

---

## 8) Enable auto-scheduling

Auto-scheduling is a hands-free mode: MeetStream scans your calendar every 24 hours and automatically schedules bots for all upcoming meetings that have a meeting link.

### Enable auto-scheduling

```
POST https://api.meetstream.ai/api/v1/calendar/auto-schedule/enable
```

### Request body

Provide a default bot configuration that will be used for all auto-scheduled bots:

```json
{
  "default_bot_config": {
    "bot_name": "MeetStream Auto Bot",
    "audio_required": true,
    "video_required": false,
    "callback_url": "https://your-domain.com/webhooks/meetstream",
    "transcription": {
      "deepgram": { "model": "nova-3", "language": "en" }
    },
    "automatic_leave": {
      "no_one_joined_timeout": 300,
      "everyone_left_timeout": 60
    }
  }
}
```

### Example cURL

```bash
curl -X POST "https://api.meetstream.ai/api/v1/calendar/auto-schedule/enable" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "default_bot_config": {
      "video_required": false,
      "callback_url": "https://your-domain.com/webhooks/meetstream"
    }
  }'
```

### Response

```json
{
  "message": "Auto-scheduling enabled successfully",
  "auto_schedule_enabled": true,
  "default_bot_config": { }
}
```

### Disable auto-scheduling

```
POST https://api.meetstream.ai/api/v1/calendar/auto-schedule/disable
```

```bash
curl -X POST "https://api.meetstream.ai/api/v1/calendar/auto-schedule/disable" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

### Check auto-schedule settings

```
GET https://api.meetstream.ai/api/v1/calendar/auto-schedule/settings
```

```json
{
  "auto_schedule_enabled": true,
  "default_bot_config": {
    "bot_name": "MeetStream Auto Bot",
    "audio_required": true,
    "video_required": false
  }
}
```

### How auto-scheduling works

1. A background job runs **every 24 hours** at midnight UTC.
2. It finds all users who have auto-scheduling enabled.
3. For each user, it looks at upcoming events in the **next 24 hours** that have a valid meeting link.
4. It skips events that already have a bot scheduled (using deduplication keys).
5. It creates bot schedules using your `default_bot_config`.
6. Bots are scheduled to join **1 minute before** the meeting starts.

> You can override individual meetings by manually scheduling them with `POST /calendar/schedule/{event_id}` and a custom `bot_config`.

---

## 9) Recurring event auto-rescheduling

For recurring meetings (weekly standups, bi-weekly syncs, etc.), MeetStream can automatically schedule a bot for the **next occurrence** after each meeting ends.

### How it works

1. A bot joins a recurring meeting.
2. After the meeting ends, MeetStream detects it was a recurring event.
3. It calculates the next occurrence from the event's recurrence rule.
4. A new bot is automatically scheduled for the next occurrence using the same configuration.

This continues indefinitely — every recurring meeting gets a bot, without manual intervention.

### Enable auto-rescheduling when scheduling

When scheduling a bot for a recurring event, set `recurring_event: true` in the request body:

```bash
curl -X POST "https://api.meetstream.ai/api/v1/calendar/schedule/evt_abc123" \
  -H "Authorization: Token <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "bot_config": { "video_required": false },
    "recurring_event": true
  }'
```

### Toggle auto-rescheduling for an existing event

You can enable or disable auto-rescheduling per event at any time:

```
POST https://api.meetstream.ai/api/v1/calendar/toggle-recurrence
```

```json
{
  "event_id": "evt_abc123",
  "recurring_enabled": true
}
```

#### Response

```json
{
  "event_id": "evt_abc123",
  "recurring_enabled": true,
  "recurrence_rule": "FREQ=WEEKLY;BYDAY=MO,WE,FR",
  "message": "Recurrence enabled for event",
  "summary": "Weekly Team Standup",
  "start_time": "2026-04-07T10:00:00Z",
  "end_time": "2026-04-07T10:30:00Z"
}
```

> This endpoint returns 400 if the event is not actually a recurring event (no recurrence rule).

### Trigger rescheduling manually

MeetStream also exposes an endpoint to manually trigger rescheduling for the next occurrence:

```
POST https://api.meetstream.ai/api/v1/calendar/auto-reschedule
```

```json
{
  "user_id": "usr_abc123",
  "event_id": "evt_abc123",
  "recurrence_rule": "FREQ=WEEKLY;BYDAY=MO,WE,FR",
  "current_start_time": "2026-04-07T10:00:00Z",
  "bot_config": { "video_required": false },
  "meeting_link": "https://teams.microsoft.com/l/meetup-join/..."
}
```

> This is primarily used internally by MeetStream after a meeting ends. You typically don't need to call it directly.

### Supported recurrence patterns

MeetStream supports standard iCalendar recurrence rules (RRULE) as surfaced by Microsoft Graph:

| Pattern | RRULE example |
|---|---|
| Daily | `FREQ=DAILY` |
| Weekly | `FREQ=WEEKLY;BYDAY=MO,WE,FR` |
| Bi-weekly | `FREQ=WEEKLY;INTERVAL=2;BYDAY=TU` |
| Monthly | `FREQ=MONTHLY;BYDAY=1MO` (first Monday) |
| Yearly | `FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=15` |

---

## 10) Real-time calendar change detection

When you connect your calendar, MeetStream sets up **Microsoft Graph change notification subscriptions** on your calendars. This enables real-time reactions to calendar changes without polling.

### What MeetStream handles automatically

| Calendar change | What MeetStream does |
|---|---|
| **Meeting rescheduled** (time changed) | Updates the bot's EventBridge schedule and `ScheduledJoinTime` to match the new time. The bot joins at the correct time. |
| **Meeting cancelled or deleted** | Cancels the EventBridge schedule and marks the bot record as `Cancelled`. No bot is created. |
| **Meeting time moved to the past** | Deletes the schedule and cancels the bot (since the meeting already happened or won't happen). |
| **New meeting added** | If auto-scheduling is enabled, a bot is scheduled for it during the next auto-schedule run. |

### How it works under the hood

1. Microsoft Graph detects a change and sends an HTTPS POST to MeetStream's webhook endpoint.
2. MeetStream validates the notification using the client state secret.
3. MeetStream fetches updated event data from the Microsoft Graph API using delta sync.
4. For each event that has an active bot scheduled:
   - **Single events:** The existing EventBridge schedule is updated in place with the new time. The bot record's `ScheduledJoinTime` is also updated so `GET /scheduled_bots` reflects the correct time.
   - **Recurring events:** All existing schedules are deleted and recreated with the updated recurrence times.
   - **Cancelled events:** The schedule is deleted and the bot record is marked `Cancelled`.

You don't need to re-sync manually or make any API calls — changes are picked up in real time via webhooks from Microsoft.

### Subscription auto-renewal

Microsoft Graph change notification subscriptions for calendar events expire after approximately **3 days** (4,230 minutes). MeetStream automatically renews expiring subscriptions:

- A background job runs **daily at 3:00 AM UTC**.
- It checks all connected users' Graph subscriptions.
- Any subscription expiring within **2 days** is renewed automatically.
- No user action is required — webhooks stay active indefinitely.

> This is more frequent than Google Calendar's 30-day watch channels. MeetStream handles the renewal schedule transparently — you will not notice any gap in change detection.

---

## 11) Disconnect your calendar

To remove the calendar integration entirely:

### API endpoint

```
DELETE https://api.meetstream.ai/api/v1/calendar/disconnect
```

### Example cURL

```bash
curl -X DELETE "https://api.meetstream.ai/api/v1/calendar/disconnect" \
  -H "Authorization: Token <YOUR_API_KEY>"
```

### Response

```json
{
  "disconnected": true,
  "user_id": "usr_abc123",
  "subscription_stopped": true,
  "events_deleted": 42,
  "schedules_cancelled": 5,
  "message": "Calendar disconnected successfully. All events and scheduled bots have been removed."
}
```

### What this does

1. Stops all Microsoft Graph change notification subscriptions (no more push notifications).
2. Cancels all pending EventBridge schedules and bot records.
3. Deletes all synced event data from MeetStream.
4. Removes stored Microsoft OAuth credentials.

> This is irreversible. To reconnect, call `POST /calendar/create_calendar` again with your credentials.

---

## End-to-end setup checklist

Here's the full flow to get Outlook Calendar integration running:

1. **Get credentials** — Register an app in Azure Portal, add Microsoft Graph permissions, and run the OAuth helper to get your refresh token
2. **Connect** — `POST /calendar/create_calendar` with your Microsoft OAuth credentials
3. **Sync** — `GET /calendar/events` to pull in your meetings
4. **Schedule** — `POST /calendar/schedule/{event_id}` to add a bot to a specific meeting
5. **Or auto-schedule** — `POST /calendar/auto-schedule/enable` to cover all meetings automatically
6. **Recurring** — Set `recurring_event: true` when scheduling, or use `POST /calendar/toggle-recurrence`
7. **Relax** — MeetStream handles calendar changes, rescheduling, cancellations, and subscription renewal from here

---

## API quick reference

| Method | Endpoint | Description |
|---|---|---|
| **Calendar connection** | | |
| POST | `/api/v1/calendar/create_calendar` | Connect Outlook Calendar |
| DELETE | `/api/v1/calendar/disconnect` | Disconnect calendar and clean up all data |
| GET | `/api/v1/calendar/calendars` | List connected calendars (live from Microsoft Graph) |
| **Events** | | |
| GET | `/api/v1/calendar/events` | Sync and list events with pagination and bot info |
| GET | `/api/v1/calendar/get_events` | List events from local database only (fast) |
| **Bot scheduling** | | |
| POST | `/api/v1/calendar/schedule/{event_id}` | Schedule a bot for an event |
| DELETE | `/api/v1/calendar/schedule/{event_id}` | Unschedule a bot for an event |
| **Scheduled bot management** | | |
| GET | `/api/v1/calendar/scheduled_bots` | List all upcoming scheduled bots |
| PATCH | `/api/v1/calendar/scheduled_bots/{bot_id}` | Update a scheduled bot (time, name, attributes) |
| DELETE | `/api/v1/calendar/scheduled_bots/{bot_id}` | Delete a specific scheduled bot |
| **Auto-scheduling** | | |
| POST | `/api/v1/calendar/auto-schedule/enable` | Enable auto-scheduling with default bot config |
| POST | `/api/v1/calendar/auto-schedule/disable` | Disable auto-scheduling |
| GET | `/api/v1/calendar/auto-schedule/settings` | Get current auto-schedule settings |
| **Recurring events** | | |
| POST | `/api/v1/calendar/auto-reschedule` | Trigger rescheduling for next recurring occurrence |
| POST | `/api/v1/calendar/toggle-recurrence` | Enable/disable auto-rescheduling per event |

---

## FAQ

### Which calendar providers are supported?
**Google Calendar** and **Outlook Calendar** (Microsoft 365 / Outlook.com) are the supported calendar providers. Your calendar can contain meetings from any platform — MeetStream detects Google Meet, Zoom, Microsoft Teams, Webex, GoToMeeting, BlueJeans, and Whereby links.

### Do I need a Microsoft 365 (work/school) account?
No. Both personal Microsoft accounts (Outlook.com, Hotmail, Live) and Microsoft 365 work/school accounts are supported. When registering your app in Azure Portal, choose **Accounts in any organizational directory and personal Microsoft accounts** to cover both.

### How do I get a Microsoft OAuth2 refresh token?
Follow **Section 1** of this guide — register an app in Azure Portal, add the required Microsoft Graph permissions, and run the provided OAuth helper (`node server_microsoft.js`) to complete the consent flow. The helper displays your refresh token in the browser.

### How far in advance does auto-scheduling look?
The auto-schedule job runs every 24 hours at midnight UTC and schedules bots for meetings happening in the **next 24 hours**. Meetings further out will be picked up in subsequent runs.

### When does the bot join relative to the meeting start time?
Bots are scheduled to join **1 minute before** the meeting's start time.

### What happens if I reschedule a meeting in Outlook?
MeetStream receives a real-time push notification from Microsoft Graph and automatically updates the bot's scheduled join time to match the new meeting time. Both the EventBridge schedule and the bot record in MeetStream's database are updated, so `GET /scheduled_bots` always shows the correct time.

### What if I cancel a meeting?
MeetStream detects the cancellation via the Microsoft Graph notification, deletes the EventBridge schedule, and marks the bot as `Cancelled`. No bot will be created for a cancelled meeting.

### What if a meeting is moved to a time that already passed?
MeetStream detects that the new time is in the past, deletes the EventBridge schedule, and cancels the bot record. This prevents a bot from being created for a meeting that can no longer be joined.

### Can I schedule bots for meetings without a meeting link?
No. MeetStream requires a valid meeting link (Google Meet, Zoom, Teams, etc.) to join. Events without a detected meeting link are skipped.

### What happens if I schedule a bot for the same event twice?
MeetStream deduplicates by event. The second call returns a `409 Conflict` with the existing bot's ID. To update the bot config, use `PATCH /calendar/scheduled_bots/{bot_id}`.

### Can I use different bot configurations for different meetings?
Yes. When you manually schedule a bot via `POST /calendar/schedule/{event_id}`, you provide the `bot_config` per event. Auto-scheduling uses your `default_bot_config` for all meetings, but you can override individual events by scheduling them manually.

### Does auto-rescheduling work with all recurrence patterns?
MeetStream supports standard iCalendar recurrence rules (RRULE) — daily, weekly, bi-weekly, monthly, yearly, and custom patterns. The next occurrence is calculated from the event's recurrence rule as returned by Microsoft Graph.

### How do I stop a recurring event from being rescheduled?
Use the toggle endpoint: `POST /calendar/toggle-recurrence` with `"recurring_enabled": false` for that event.

### Do I need to worry about Microsoft Graph subscriptions expiring?
No. MeetStream automatically renews Microsoft Graph change notification subscriptions before they expire. A daily background job checks for subscriptions expiring within 2 days and renews them. Your real-time calendar sync stays active indefinitely without any action on your part.

### What data is deleted when I disconnect my calendar?
Everything: Graph subscriptions are stopped, pending bot schedules are cancelled, synced event data is deleted, and Microsoft OAuth credentials are removed from storage. This is irreversible.

### Is my Outlook Calendar data stored securely?
Yes. OAuth credentials are stored in AWS Systems Manager Parameter Store as encrypted `SecureString` parameters. Event data is stored in DynamoDB with encryption at rest. MeetStream does not store your Microsoft password.

### Can I schedule bots for all occurrences of a recurring event at once?
Yes. Pass `"schedule_all_occurrences": true` in the request body when scheduling. You can limit the number of occurrences with `"occurrence_limit"` (default 52). Each occurrence gets its own bot and EventBridge schedule.

### How do I schedule a bot for a specific occurrence of a recurring event?
Pass `"occurrence_date": "2026-04-14T10:00:00Z"` in the request body. MeetStream will schedule a bot for that specific occurrence only.

### Can I cancel bots for future occurrences only?
Yes. When unscheduling a recurring event, pass `"from_date": "2026-05-01T00:00:00Z"` to cancel only occurrences from that date forward. Occurrences before that date keep their scheduled bots.

### My client secret expired — what do I do?
Generate a new client secret in Azure Portal under your app's **Certificates & secrets**, then re-run the OAuth helper to get a fresh refresh token, and call `POST /calendar/create_calendar` again with the new credentials. MeetStream will replace the old connection automatically.

---

For webhook event handling, see the [Webhook Events Guide](/guides/webhooks/webhooks-and-events).
For creating your first bot without calendar integration, see the [First Bot Quickstart](/guides/get-started/create-your-first-bot).
For Google Calendar integration, see the [Google Calendar Integration Guide](/guides/app-integrations/using-credentials-with-meetstream-api).