Microsoft Graph API v1.0 で Outlook.com(個人)アカウントの予定を作成しても、isOnlineMeeting: true を指定したのに onlineMeeting: null のまま—という相談が各所で増えています。本記事は、その“なぜ?”に対する結論と根拠、確実な切り分け手順、現実的な回避策、そして設計の勘所までを一気通貫で解説します。
結論(最初に要点)
- 個人用 Outlook.com アカウントでは、Graph API の予定作成時に Teams/Skype のオンライン会議 URL を自動生成できません。
isOnlineMeetingやonlineMeetingProviderを指定しても、レスポンスはisOnlineMeeting: false、onlineMeeting: nullのままになるのが仕様です。- これは設定ミスやスコープ不足ではなく、アカウント種別(個人 vs 仕事/学校)に起因する機能差です。
- 完全自動化が必要なら Microsoft 365(仕事/学校)アカウントを使ってください。個人アカウントでは自動化できません。
再現する現象
POST /v1.0/me/events
{
"subject": "APIテスト",
"start": { "dateTime": "2025-11-01T10:00:00", "timeZone": "Tokyo Standard Time" },
"end": { "dateTime": "2025-11-01T10:30:00", "timeZone": "Tokyo Standard Time" },
"isOnlineMeeting": true,
"onlineMeetingProvider": "skypeForConsumer" // または "teamsForBusiness"
}
期待:Teams/Skype の参加 URL が onlineMeeting.joinUrl に入る。
実際:"isOnlineMeeting": false、"onlineMeeting": null、"onlineMeetingProvider": "unknown" など。
なぜ起きるのか(仕様上の制限)
Graph のオンライン会議機能は大きく 2 系統あります。
- Outlook カレンダー API で「オンライン会議付きの予定」を作る
POST /me/eventsでisOnlineMeeting: trueとonlineMeetingProviderを指定する方法。
ただし “組織(仕事/学校)でオンライン会議プロバイダーが有効”な場合にのみ有効に働きます。個人用 Outlook.com にはこの前提がありません。 - Cloud Communications API(
/onlineMeetings)で Teams 会議オブジェクトを作る
これは 予定に紐づかない単独の会議 を作る API ですが、個人アカウントの委任トークンは非対応です。アプリ権限も基本は組織テナント前提です。
結果として、個人アカウント × Graph API で「自動的に参加 URL を付与した予定」を作ることはできません。ドキュメントに skypeForConsumer や teamsForBusiness が列挙されていても、個人アカウントでは指定が黙殺されるか unknown 扱いになります。
まずやるべき切り分けチェック
以下の 3 ステップで、仕様による制限かどうかを 5 分で確定できます。
1) カレンダーの対応プロバイダーを確認
GET /v1.0/me/calendar?$select=allowedOnlineMeetingProviders,defaultOnlineMeetingProvider
Authorization: Bearer <token>
個人アカウントでは典型的に次のいずれかになります。
[](空)["skypeForConsumer"](列挙されても実際は使えない)["unknown"]
teamsForBusiness が見えない限り、Teams 会議 URL は自動生成されません。
2) 同じリクエストを「仕事/学校」アカウントで実行
Microsoft 365(Business/Education)のユーザーで同じ JSON を投げると、onlineMeeting.joinUrl を含むレスポンスが返るはずです。ここで差が出れば、アカウント種別による機能差が確定します。
3) /onlineMeetings エンドポイントの対応可否
POST /v1.0/me/onlineMeetings
{
"startDateTime": "2025-11-01T10:00:00Z",
"endDateTime": "2025-11-01T10:30:00Z",
"subject": "テスト会議"
}
個人アカウントの委任権限では 非対応です。仕事/学校アカウント+適切な権限・ポリシーでのみ利用できます。さらに、この API は「予定に紐付かない会議」を作るため、作成してもカレンダーには自動で載りません(予定に貼りたい場合は自前で URL を本文やロケーションへ反映)。
「設定やスコープの問題では?」に対する回答
よくある誤解を先に潰します。
- OAuth スコープ追加では解決しません。
Calendars.ReadWriteを満たしていれば予定は作れますが、オンライン会議の自動生成はアカウント種別の制約です。 - Beta エンドポイントでも同じ。 サポートされないアカウントで挙動が変わることはありません。
- Outlook クライアント側の「すべての会議をオンラインにする」設定は UI での作成に影響しますが、API 経由の予定生成には保証されません。個人アカウントではプロバイダー自体が有効化されていないため、期待通りにならないのが普通です。
確認用スニペット集(そのまま試せる)
cURL(予定を作成)
curl -X POST https://graph.microsoft.com/v1.0/me/events \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"subject": "オンライン会議付きの予定?",
"start": { "dateTime": "2025-11-01T10:00:00", "timeZone": "Tokyo Standard Time" },
"end": { "dateTime": "2025-11-01T10:30:00", "timeZone": "Tokyo Standard Time" },
"isOnlineMeeting": true,
"onlineMeetingProvider": "teamsForBusiness"
}'
想定レスポンス(個人アカウントの例)
{
"id": "AAMkAGY...",
"subject": "オンライン会議付きの予定?",
"isOnlineMeeting": false,
"onlineMeeting": null,
"onlineMeetingProvider": "unknown",
...
}
PowerShell(Graph SDK)
Connect-MgGraph -Scopes "Calendars.ReadWrite"
$payload = @{
subject = "APIテスト"
start = @{ dateTime = "2025-11-01T10:00:00"; timeZone = "Tokyo Standard Time" }
["end"] = @{ dateTime = "2025-11-01T10:30:00"; timeZone = "Tokyo Standard Time" }
isOnlineMeeting = $true
onlineMeetingProvider = "teamsForBusiness"
}
New-MgUserEvent -UserId me -BodyParameter $payload |
Select-Object subject,isOnlineMeeting,onlineMeetingProvider
アカウント種別ごとの可否早見表
| ユースケース | Outlook.com(個人) | Microsoft 365(仕事/学校) |
|---|---|---|
POST /me/events で isOnlineMeeting: true(Teams) | ✕(無視される/unknown) | ◯(onlineMeeting.joinUrl が返る) |
POST /me/events で onlineMeetingProvider: "skypeForConsumer" | ✕(列挙はあっても実質不可) | — |
POST /me/onlineMeetings(Cloud Communications) | ✕(委任は非対応) | ◯(ただし予定に自動反映されない) |
GET /me/calendar で allowedOnlineMeetingProviders | [] / ["skypeForConsumer"] / ["unknown"] | ["teamsForBusiness", ...] 等が見える |
「以前は動いていた?」について
個人アカウントで一時的に URL が付いたように見えた、という報告はあります。多くは以下のいずれかです。
- Outlook クライアント側の自動処理にユーザーが引っ張られた(UI では付いたが API では付かない)。
- サーバー側の暫定挙動やロールアウト途中の仕様で一瞬だけ通った。
- 実は仕事/学校アカウントで試していた(別プロファイル/別メールボックス)。
いずれにしても現在の仕様では個人アカウントに対する API 自動生成は期待できないため、再現性のある設計に切り替えるべきです。
実務的な回避策(比較表)
| 方法 | 概要 | 長所 | 短所 / 注意点 |
|---|---|---|---|
| 仕事/学校アカウントを利用 | Microsoft 365(Business/Education)テナントで予定作成。isOnlineMeeting: true + teamsForBusiness で URL 自動生成。 | 完全自動化。会議 URL が onlineMeeting.joinUrl に入り、招待メールにも反映。 | アカウント切替・ライセンス費用が前提。B2C/個人向けプロダクトには不向き。 |
| Cloud Communications API で会議だけ作成 | POST /users/{id}/onlineMeetings(組織前提)で会議 URL を取得し、別途予定本文やロケーションへ埋め込む。 | 会議の詳細を細かく制御可能。ボット統合など拡張性。 | 個人アカウント委任は非対応。さらに「予定に自動で載らない」ため、連携実装が必要。 |
| 手動運用 | API では予定だけ作成し、ユーザーが Outlook/Teams から「オンライン会議を追加」。 | 導入が簡単。既存の個人アカウントをそのまま活用。 | 自動化されない。ユーザー操作に依存し、取りこぼしリスク。 |
堅牢な実装パターン(サンプル設計)
パターン A:組織テナントで完全自動化
- 前提確認:対象ユーザーのカレンダーで
allowedOnlineMeetingProvidersにteamsForBusinessが含まれる。 - 予定作成:
isOnlineMeeting: true+onlineMeetingProvider: "teamsForBusiness"。 - 確認:レスポンスの
onlineMeeting.joinUrlを取り出し、用途に応じて保存。
パターン B:会議を別 API で作って予定へ貼る(組織のみ)
POST /users/{id}/onlineMeetingsで会議を作成(アプリ権限+アプリアクセス ポリシー)。joinUrlを予定のbody.contentやlocation.displayNameに設定してPATCH /me/events/{id}。
パターン C:個人アカウント向けの現実解
- API では「日付・時間・参加者など」予定の骨格だけを作る。
- UI 上では「会議 URL は後で追加してください」と明示表示(メール・UI・通知)。
- ユーザーが URL を追加したかどうかは、後続の
GET /me/events/{id}?$select=isOnlineMeeting,onlineMeetingで任意で監視する。
トラブルシュート・チェックリスト
- レスポンスが
isOnlineMeeting: false:アカウント種別を確認。個人なら仕様どおり。 onlineMeetingProviderを省略すると動く?:組織では既定プロバイダーが Teams なら生成されることがあります。個人では変わりません。onlineMeetingUrlではなくonlineMeeting.joinUrlを読む:前者は廃止予定の互換プロパティです。- Graph SDK 利用時の型:
OnlineMeetingProviderTypeにteamsForConsumerは存在しません(指定するとエラー)。
API 実行前に見るべきプロパティ
| API | 確認したいプロパティ | 意味 | 個人アカウントの典型値 |
|---|---|---|---|
GET /me/calendar | allowedOnlineMeetingProvidersdefaultOnlineMeetingProvider | このカレンダーがどのオンライン会議プロバイダーに対応しているか | [] / ["skypeForConsumer"] / ["unknown"] |
POST /me/events | isOnlineMeetingonlineMeetingProvider | 予定にオンライン会議を付与するための指定 | 指定しても黙って無視される |
POST /me/onlineMeetings | — | Teams 会議オブジェクトの作成(予定とは別物) | 委任(個人)は非対応 |
サンプル:生成できない場合の安全なフォールバック
// 擬似コード(個人でも動く安全策)
const event = await graphClient.api('/me/events').post({
subject: '面談(URLは後で追加)',
start: { dateTime: '2025-11-01T10:00:00', timeZone: 'Tokyo Standard Time' },
end: { dateTime: '2025-11-01T10:30:00', timeZone: 'Tokyo Standard Time' },
body: { contentType: 'HTML', content: 'この予定はオンライン会議URL未設定です。Outlook/Teamsから追加してください。' }
});
// 後続でUIやメール通知を出す
notifyUser('会議URLを追加してください', event.id);
セキュリティと権限の観点
- 予定の作成自体は
Calendars.ReadWrite(委任)で足ります。 - Cloud Communications(
/onlineMeetings)をアプリ権限で使う場合は、組織テナントでのアプリアクセス ポリシー設定が必要です。 - 個人アカウントではこれらが前提から外れるため、権限追加の方向での解決はできません。
設計指針(プロダクト/業務フロー)
- B2C/個人ユーザー向けアプリ:「予定だけ API で作り、URL はユーザーが後で追加」という体験に寄せる。手順を UI にビルトイン(ボタン・ガイド・チェック)し、抜け漏れ検知のために予定の
onlineMeetingを後追いチェック。 - 業務内製ツール:アカウントを Microsoft 365(仕事/学校)に統一し、
isOnlineMeeting: trueで完結させる。必要なら/onlineMeetingsを併用して高度な会議制御を実現。 - サポート文言:エラーではなく仕様差であることを明示。「Outlook.com 個人アカウントは API によるオンライン会議自動付与をサポートしていません」という定型メッセージを用意。
よくある質問(FAQ)
Q. onlineMeetingProvider を省略すると通るケースがある? A. 組織では既定プロバイダー(Teams)が有効なら通ることがあります。個人では変わりません。 Q. skypeForConsumer を指定すれば個人でも作れる? A. 値として列挙されますが、実際に URL が生成されないのが通常の挙動です。 Q. 将来的に個人アカウントでもサポートされる? A. 現時点では期待できません。要件が「自動生成必須」なら、仕事/学校アカウントへの移行を検討してください。 Q. onlineMeetingUrl と onlineMeeting.joinUrl の違いは? A. onlineMeetingUrl は互換用で非推奨。参加 URL は onlineMeeting.joinUrl を使います(組織テナントでのみセット)。
実装チェックリスト(貼って使える)
- [ ]
GET /me/calendarでallowedOnlineMeetingProvidersを確認(teamsForBusinessがあるか)。 - [ ] 個人アカウントなら自動生成を諦め、UI/運用フォールバックを設計。
- [ ] 組織アカウントなら
isOnlineMeeting: trueとonlineMeetingProvider: "teamsForBusiness"を指定。 - [ ] 返却 JSON の
onlineMeeting.joinUrlを保存・通知し、クライアントへ反映。 - [ ]
/onlineMeetingsを使う場合は予定連携(URL 埋め込み)を別途実装。
まとめ
本件の本質は「設定」でも「スコープ」でもなく、個人アカウントに対するサポート範囲です。Graph の設計に従えば、Outlook.com(個人)で予定作成時にオンライン会議 URL を自動生成することはできません。必要なのは、要件とアカウント種別を最初に一致させること。完全自動化が求められるなら Microsoft 365 の仕事/学校アカウントを使い、個人向けでは「予定のみ API → URL は後で追加」というユーザー体験を丁寧にデザインしてください。

コメント