Teams Notion Webhook の設計 : hkob の雑記録 (516)

はじめに

hkob の雑記録の第516回目(連続89日目)は、Teams から Notion の日付なしタスクを生成する Webhook の設計について、Notion AI とディスカッションした件を記録しておきます。

第一案: メンションからタスク化

最初の壁打ちはここから開始しました。

最初の壁打ち

実際に Power Automate で確認したところ、チームやチャンネルを指定する必要があるようでした。そこで、以下のように全てのチャンネルのメンションが取れるのか確認してみました。

全てのチャンネルメンション?

その後、複数のチームのメンションが必要か問い合わせがあったので以下のように回答しました。

複数チームは可能?

Microsoft Graph で Entra ID アプリ登録という案が出ましたが、多分法人に依頼が必要で難しそうです。これが難しいことを伝えると以下のような代替案を出してきました。

現実的な代替案

第二案: Power Automate フローを利用

そういえば GAS を運用していた時に、Teams to Notion の Power Automate フローを作成していたことを思い出しました。この時は先日の GAS によるカレンダータスク登録と同じスクリプト内に記載されていたものです。Power Automate から Google Spreadsheet に書き込むことで、GAS のトリガが発動し、タスクを生成していました。今回は後半部分を Webhook にすればいいわけです。その時の記事はこちらです。2022年の8月に実装していました。この仕組みは GAS の運用を止めた時点で使えなくなってしまったので、最近は全く使っていませんでした。

Teams から日付未確定のタスクを作成: Notion 解説 (64) - hkob’s blog

ということで第二案を以下のように提案してみました。

第二案の提案

やはりこの方法の方が筋がよさそうです。Webhook がそのまま使えるかについては50/50とのことでした。

moodle webhook がそのまま利用可能か?

このあと議論した上で、最後の質問に答えたところ、設計書を作成してくれました。今回は、moodle webhook とは別の worker を作成することにしました。単純にした方がトラブルにならないと思うためです。ただ、今後 Notion クレジットが worker の数でカウントされるようであれば、統合も今後検討していこうと思います。

最終決定

最終設計書

以下は生成された最終設計書です。明日、これに基づいて実装していきます。

目的

Microsoft Teams のメッセージを、手動フロー(Power Automate)で Notion の Tasks にタスクとして登録する。見落とし防止・GTD の Inbox 化。

スコープ

  • Teams → Notion Tasks の片方向同期(Teams が正)。
  • 対象: 自分が「タスク化したい」と判断した Teams メッセージ(手動実行)。
  • 仕様は 作成のみを基本とする(更新/削除は後回し)。必要なら将来拡張。

全体アーキテクチャ(案)

  1. Microsoft Teams
    • タスク化したいメッセージをユーザーが選択
  2. Power Automate
    • トリガ: 「選択されたメッセージに対して(V2)」等の手動実行
    • 重要情報(team/channel、messageId、webUrl、本文、送信者、日時)を抽出
    • Worker(Teams 用)に HTTP POST(Webhook)送信
  3. Worker(Notion Workers)
    • 受信検証(共有シークレット)
    • 冪等性チェック(External ID)
    • Notion Tasks にタスクを作成(最小プロパティ)

前提(既存資産)

  • Tasks データソースに冪等性キー用の External ID プロパティが存在する。[1]
  • Worker が外部から到達可能な Webhook エンドポイントを持てる(既存 webhook と同様)。
  • Power Automate から HTTP リクエスト送信が可能(「HTTP」アクション)。

Power Automate 側の可否

可能。今回は「メンション検知」ではなく 手動起動で実装する。

  • トリガ: 「選択されたメッセージに対して(V2)」
  • アクション: HTTP(POST)で Worker の Webhook URL に JSON を送信

※ 初回は「テスト実行して payload を保存」→ Worker の入力スキーマを確定する。

Webhook(Worker)I/F 設計(案)

エンドポイント

  • POST /webhooks/teams-mention(例)

(注)メンション検知ではなく「Teams メッセージの手動タスク化」用途のため、名前は teams-message 等に変更してよい。

認証(推奨)

  • 共有シークレット方式(最小構成)
    • Header: X-Webhook-Secret: <secret> もしくは
    • HMAC 署名: X-Signature: sha256=<hex>(body の HMAC-SHA256)

(Power Automate の HTTP アクションは固定ヘッダー付与が容易なので、まずは共有シークレットで十分)

リクエスト body(正規化ペイロード案)

{
  "event": "teams.mention.created",
  "occurredAt": "2026-06-06T12:34:56Z",
  "tenantId": "...",
  "conversation": {
    "type": "channel",
    "teamId": "...",
    "teamName": "...",
    "channelId": "...",
    "channelName": "..."
  },
  "message": {
    "id": "...",
    "webUrl": "https://teams.microsoft.com/l/message/...",
    "subject": "...",
    "text": "...",
    "from": {
      "id": "...",
      "displayName": "..."
    }
  },
  "mentions": [
    { "id": "...", "displayName": "...", "email": "..." }
  ]
}

レスポンス(案)

  • 200 OK + { "status": "ok" }(正常)
  • 401 Unauthorized(secret 不一致)
  • 409 Conflict(冪等性により既に処理済み)
  • 500(その他)

冪等性キー(External ID)の設計

基本方針

同一メンションが重複通知されても、Tasks が重複作成されないように External ID で制御する。

形式案

  • チャネル投稿: teams:channel:<teamId>:<channelId>:message:<messageId>
  • チャット投稿: teams:chat:<chatId>:message:<messageId>

(最初は conversation.type を channel|chat の 2 択で正規化すると扱いやすい)

Tasks 側のマッピング(案)

  • Task name:
    • 【Teams】<from.displayName>: <subject or 先頭N文字>
  • Summary:
    • text(長すぎる場合は切り詰め、原文は Link で参照)
  • Link:
    • message.webUrl
  • External ID:
    • 上記の冪等性キー
  • Date:
    • 付与しない(Inbox として運用) or occurredAt を入れる(運用次第)

※ Status / Assignee は更新しない(手動運用に任せる)。同期で触るのは最小限。

エラーハンドリング / リトライ

  • Power Automate は失敗時に自動リトライする可能性があるため、Worker は冪等性が必須。
  • Worker 側は失敗理由をログに残し、4xx はリトライ不要、5xx はリトライ可とする。

セキュリティ / 運用

  • Worker 側で許可する tenantId をホワイトリスト化(可能なら)。
  • 個人情報(メッセージ本文)を Notion に保存するかは運用判断。
    • 保存しない方針なら Summary を最小化(例: 「Teams でメンション」+送信者+リンクのみ)。
  • Secrets(Webhook secret)は Notion ページやログに貼らず、Workers の env に保存。

シーケンス図(案)

シーケンス図

未決事項(確定が必要)

  • Power Automate トリガの対象:
    • チャネルのみ / チャットも含む
    • 自分のみ / 複数ユーザー
  • Tasks に保存する本文の範囲(要件・個人情報)
  • 「更新」扱い(メッセージ編集)を追従するか(当面は無視でよい)

おわりに

未決事項などが残っていますが、これらは実装する段でまたディスカッションしながら決めていこうと思います。

https://hkob.notion.site/hkob-16dd8e4e98ab807cbe3cf3cc94cdfe0f?pvs=4hkob.notion.site