Incoming Webhook(受信Webhook)とは、SlackやDiscordなどのチャットツールが発行する専用URLへ、外部のプログラムがJSONをHTTP POSTするだけでメッセージを投稿できる仕組みです。通知専用のBotを開発せず、curlで監視アラートをチャンネルへ送れます。ただしURLに含まれる秘密情報の管理は必要で、Teams Workflowsでは設定によって別途認証トークンも必要です。ただしURL形式・本文のキー・送信上限はサービスごとに違い、Microsoft Teamsの旧方式(Office 365コネクタ)は2026年5月に停止しました。この記事では主要5サービスの発行手順と送信例を並べ、Incoming Webhookで足りない場面の見分け方まで整理します。
まとめ:Incoming Webhookの要点とサービス別の現状
- 仕組み:受け手のチャットツールが発行したURLへJSONをPOSTすると、決められたチャンネルに投稿される。多くのサービスではURL自体が認証情報を兼ねる。
- 本文のキー:Slack・Google Chatは
text、Discordはcontent、LINE WORKSはbody.text、Teams Workflowsは Adaptive Card を入れたattachments。 - 送信上限:Slackはチャンネルごとに毎秒1件、Google Chatはスペースごとに毎秒1件、LINE WORKSはドメイン全体で毎分120件。超えると429が返る。
- 廃止の状況:止まったのはTeamsのOffice 365コネクタ(2026年5月18〜22日に無効化)。Slackはアプリ方式が現役で、移行を求められているのは旧来のカスタムインテグレーションだけ。
- 足りない場面:発言の受信や動的な送信先には追加の仕組みを検討する。編集はDiscordのWebhook用APIやTeamsのフローでも対応できるため、サービス別に判断する。
Incoming Webhookの仕組みとOutgoing Webhookとの違い
Incoming Webhookは「受け手が窓口のURLを用意し、送り手はそこへPOSTするだけ」という一方通行の連携です。Webhook一般の定義やAPIとの違いはWebhookとは?読み方・仕組み・APIとの違いを実際のHTTPリクエストで解説にまとめているので、ここではチャットツールへの通知に絞ります。
Incoming(受信)とOutgoing(送信)の向き
「Incoming」はチャットツールから見て外から入ってくる向きを指し、逆向きのOutgoing Webhookはチャンネルでの発言をきっかけに外部のURLへリクエストを送る機能です。
| 種類 | 向き | URLを用意する側 | 典型的な用途 |
|---|---|---|---|
| Incoming Webhook | 外部 → チャット | チャットツール | 監視・CIの通知 |
| Outgoing Webhook | チャット → 外部 | 外部のサーバー | 発言を合図に処理 |
SlackのOutgoing Webhookは旧来のカスタムインテグレーションに属し、新規ならEvents APIを使います。発言を外部で受ける側は受信サーバーの実装になるので、署名検証や再送への備えはWebhookの作り方と実装方法|受信側の署名検証・冪等性と送信側の再送をNode.js・Pythonで解説を参照してください。
URLそのものが認証情報になる前提
Incoming WebhookのURLには、投稿先を特定する識別子と秘密のトークンが埋め込まれています。SlackとDiscordはURLのパス末尾、Google Chatはクエリの token が秘密の部分です。Googleのクイックスタートは token を「a unique value that must be kept secret」と書き、公開リポジトリにURLを載せないよう警告しています。URLだけで認証する方式では、URLを知る第三者も投稿できるため、パスワードと同じ扱いで保管します。Teams Workflowsでは、呼び出し元をテナント内ユーザーに限定して認証を要求する設定もあります。
主要5サービスのIncoming Webhook比較
各社の公式ドキュメントで確認した仕様を1つの表に並べました(2026年10月15日時点)。違いが大きいのは本文のキーと、送信上限がどの単位にかかるかです。
| 項目 | Slack | Discord | Teams(Workflows) | Google Chat | LINE WORKS |
|---|---|---|---|---|---|
| URLのホスト | hooks.slack.com | discord.com | *.api.powerplatform.com | chat.googleapis.com | webhook.worksmobile.com |
| 本文のキー | text | content | attachments | text | body.text |
| 本文サイズの上限 | — | content 2,000字 | 28KB | — | — |
| 送信上限 | 毎秒1件/チャンネル | 応答ヘッダーで通知 | 性能プロファイルで変動 | 毎秒1件/スペース | 毎分120件/ドメイン |
| 名前・アイコンの上書き | 不可 | 可 | 不可 | 登録時のみ | 不可 |
| 投稿後の編集 | 別APIが必要 | 可 | 更新アクションが必要 | APIが必要 | 不可 |
| 無効URLへの応答 | 404 no_team | 404 code 10015 | 未検証 | 403 | 400 |
「本文サイズの上限」は公式に明記がある値だけを載せました。Teamsの約28KBは投稿アクションのメッセージサイズ上限で、受信トリガーの流量はPower Automateの性能プロファイルで決まります(旧コネクタの毎秒4件とは別)。最下行の「無効URLへの応答」は、存在しないURLへ実際にPOSTして返ってきた値です(2026年10月15日に実測)。SlackはJSONを壊して送っても no_team が返り、URLの検証がJSONの解釈より先に行われます。「invalid_payload が出ないからJSONは正しい」とは言えないので、切り分けはURLの確認から始めます。
送信上限の適用単位とURL追加の制約
表の「送信上限」は単位まで読んでください。Google Chatの公式ドキュメントは「1 request per second, shared among all webhooks in the space」と書いており、同じスペースにWebhookを3本登録しても合計で毎秒1件です。LINE WORKSも「Webhook URL 単位にかかる制限ではありません」と明記し、5本のURLで毎分120件を分け合います。URLを増やしても流量は増えないので、アラートが連打される構成なら送信側で1分ごとに1通へまとめます。
SlackでIncoming Webhookを使う手順
SlackのWebhook URLはSlackアプリを作って発行します。Slackの公式ガイドの手順は次の4段階です。
- アプリ管理画面(api.slack.com/apps)で「Create New App」からアプリを作り、ワークスペースを選ぶ
- 左メニューの「Incoming Webhooks」で「Activate Incoming Webhooks」をオンにする
- 「Add New Webhook to Workspace」を押し、投稿先のチャンネルを選んで許可する
- 一覧に追加された
https://hooks.slack.com/services/T…/B…/…形式のURLをコピーする
curl -X POST -H "Content-Type: application/json" \
-d '{"text": "デプロイが完了しました"}' \
"$SLACK_WEBHOOK_URL"
成功すると HTTP 200 と本文 ok が返ります。アプリ方式では「You cannot override the default channel (chosen by the user who installed your app), username, or icon」とされ、JSONに channel を書いても投稿先は変わりません。別のチャンネルへ送るなら手順3でURLをもう1本発行します。
送信上限はチャンネルごとに毎秒1件で、Incoming Webhookもchat.postMessageと同じ枠です。超えると429と Retry-After ヘッダーが返ります。エラー文字列の切り分け表、Block Kitでの整形、429を待つ再送コードはSlack Incoming Webhookの実装手順:URL発行・Block Kit整形・SDK送信と429対策で扱っています。
DiscordでWebhook URLを発行して送る手順
Discordの公式ヘルプでは、「サーバー設定」の「連携サービス」タブで「ウェブフックを作成」を押し、通知先のテキストチャンネルを選びます。「ウェブフックURLをコピー」で取れるURLは https://discord.com/api/webhooks/{webhook.id}/{webhook.token} の形です。
curl -X POST -H "Content-Type: application/json" \
-d '{"content": "ビルドが成功しました", "username": "CI"}' \
"$DISCORD_WEBHOOK_URL?wait=true"
Slackとの違いは4点あります。いずれもExecute Webhookのリファレンスに書かれた仕様です。
- 本文は
contentで最大2,000文字。リッチな表示はembeds(最大10個)を使う usernameとavatar_urlでメッセージごとに表示名とアイコンを変えられる- 既定(
wait=false)は 204 No Content を返し、保存に失敗してもエラーにならない。?wait=trueを付けると作成されたメッセージが返り、そのIDで後から編集・削除できる - URLの末尾に
/slackを付けるとSlack形式のJSONを、/githubを付けるとGitHubのWebhookを受け付ける。ただしSlack互換はSlackのchannel・icon_emoji・mrkdwnに対応せず、GitHub互換も表示できるイベントが限られる
フォーラムチャンネルへ送る場合は、既存スレッドの thread_id をクエリに付けるか、新規スレッド名を thread_name で渡す必要があります。送信上限の固定値は公開されておらず、Discordは「rate limits should not be hard coded into your app」として応答ヘッダーと429の retry_after で制御するよう求めています。チャンネルでの操作に反応させたい要件はWebhookではできないので、Discord Botの仕組みと作り方|既製Botと自作の判断基準を実装視点で解説の範囲になります。
PythonのurllibからDiscordへ送ると403になる理由
Python標準の urllib.request で、User-Agentを指定せずにDiscordのWebhookへPOSTすると、HTTP 403 と本文 error code: 1010 が返りました(Python 3.9.6で実測)。既定のUser-Agent(Python-urllib/3.9)がCloudflareに弾かれるためで、同じ要求をUser-Agentだけ変えて送ると404 Unknown Webhook まで届きました。Discordの開発者リファレンスも、有効なUser-Agentの無い要求は「may be blocked and return a Cloudflare error」と書いています。Slackでは同じコードがそのまま通るので、Slack向けのサンプルを流用したときに起きやすい失敗です。
Microsoft TeamsのIncoming Webhook:旧コネクタ停止とWorkflowsへの移行
Teamsで長く使われてきた「Incoming Webhook」はOffice 365コネクタの一種で、すでに動きません。MicrosoftのMicrosoft 365 Developer Blogは2026年4月14日の更新で、無効化のロールアウトを2026年5月18日に始め、5月22日に完了すると告知しました。期限は2024年末から何度も延長されたため、古い記事の日付は当てになりません。日本語版のMicrosoft Learn「受信 Webhook を作成する」は、冒頭に「非推奨に近づいています」と停止前の表現を残したままです(2026年10月15日確認)。
| 時期 | 出来事 |
|---|---|
| 2025年1月31日 | コネクタのWebhook URLを新形式へ更新する期限 |
| 2025年11月30日 | WorkflowsのWebhookで旧 logic.azure.com のURLが停止 |
| 2026年2月5日 | WorkflowsがMessageCard形式に対応 |
| 2026年5月18〜22日 | Office 365コネクタを無効化 |
2025年11月30日の項目は、すでにWorkflowsへ移った人にも関係します。Power Automateのトラブルシューティングによると、Teams WebhookトリガーやHTTPトリガーの旧URL(logic.azure.com)はこの日に動かなくなり、デザイナーに表示される新しいURLへの差し替えが必要でした。2024〜2025年前半に作ったWorkflowsのURLを設定ファイルに残したままなら、通知が止まっている可能性があります。
Workflowsで受信Webhookを作る手順
Teamsでチャネル名の横の「…」から「ワークフロー」を開き、「Webhook アラートをチャネルに送信する」テンプレートを選んで保存すると、Webhookのリンクが発行されます。Microsoftのサポート記事によると、このテンプレートとTeams Webhookトリガーにプレミアムライセンスは要りません。以下の送信例は、トリガーの認証設定が「Anyone」の場合を対象にしています。テナント内ユーザーに限定する設定では認証トークンが必要です。本文はAdaptive Cardを attachments に入れます。
curl -X POST -H "Content-Type: application/json" "$TEAMS_WORKFLOW_URL" -d '{
"type": "message",
"attachments": [{
"contentUrl": null,
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [{"type": "TextBlock", "text": "夜間バッチが失敗しました", "wrap": true}]
}
}]
}'
旧コネクタとの違いで移行時に困るのは次の3点です。1つ目に、投稿者は既定のWorkflows bot(Flow bot)で固定され、表示名やアイコンは変えられません。2つ目に、MessageCard形式は表示されてもボタン(HttpPostアクション)は動かないため、操作ボタンが要るならAdaptive Cardへ書き換えます。3つ目に、ワークフローは作成した個人に紐づくので、その人が退職すると孤立フローになります。Learnは共同所有者の追加を勧めており、運用で使うなら作成直後に設定しておくべきです。メンション付きの投稿や承認カードの組み方はPower AutomateのTeams連携とは?カード通知・メンション・承認の実装と権限で解説しています。
Google ChatとLINE WORKSのIncoming Webhook
Google Chat:スペースへの登録とthreadKeyによる通知の集約
Googleのクイックスタートは、Google ChatにアクセスできるBusinessまたはEnterpriseのGoogle Workspaceアカウントを前提条件にしています。登録はブラウザ版のChatからだけで、モバイルアプリでは設定できません。スペース名の横の矢印から「アプリとインテグレーション」→「Webhook を追加」と進み、名前を付けて保存したあと「その他」→「リンクをコピー」で https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN 形式のURLを取得します。ボタンが押せない場合は、組織の管理者がWebhookの利用を許可していません。
curl -X POST -H "Content-Type: application/json; charset=UTF-8" \
-d '{"text": "障害が復旧しました", "thread": {"threadKey": "incident-1024"}}' \
"$GCHAT_WEBHOOK_URL&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
threadKey に任意の文字列を入れ、URLに messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD を足すと、同じキーのスレッドがあれば返信になり、無ければ新しいスレッドが立ちます。障害IDをキーにすれば、発生から復旧までの通知が1つのスレッドに並びます。
LINE WORKS:URLは5本まで・上限はドメインで共有
LINE WORKSはアプリディレクトリの無料アプリ「Incoming Webhook」を追加し、トークルームに招待したBotのメニューからURLを発行します。Developersの仕様では、追加できるURLは5つまで、送信上限は1ドメインあたり毎分120件で全URLが共有します。本文は {"body": {"text": "…"}} の形で、画像を含むファイルの送信や、トークルームからのメッセージ送信には対応していません。設定画面の手順とJSONの詳細はLINE WORKS Incoming Webhookの設定手順とJSON送信仕様|5URL・120req/minの上限にまとめています。
Incoming Webhookの廃止状況とサービス別の移行対応
Incoming Webhookの廃止状況は、サービスと提供方式を分けて確認する必要があります。2026年10月15日時点で、各社の公式ドキュメントに書かれている状況は次のとおりです。
| サービス | 現状 | 対応 |
|---|---|---|
| Teams(Office 365コネクタ) | 2026年5月に無効化済み | Workflowsで作り直す |
| Teams(Workflows) | 現役 | 旧URLは差し替え済みか確認 |
| Slack(アプリ方式) | 現役 | 不要 |
| Slack(レガシー統合) | アプリ方式への移行を推奨 | アプリで再発行 |
| Discord・Google Chat・LINE WORKS | 停止の告知なし | 不要 |
Slackのレガシー版ページは「you should switch to using the same functionality with a Slack app instead」と移行を促していますが、停止日は書かれていません。移行で失うのは送信時のチャンネル・名前・アイコンの上書きで、送信コードの大半はそのまま動くと公式も説明しています。似た名前の終了ニュースとして、LINE Notifyは2025年3月31日に提供を終えました。こちらはWebhookではなくLINEの通知APIで、移行先の実装はLINE Notify終了後の移行実装|Messaging APIへの置き換え手順と通知コードで扱っています。
Incoming Webhookで足りない場面とBot・APIへの切り替え基準
Incoming Webhookは「決まった場所に、一方通行で、ときどき投稿する」用途で、通知専用Botの実装を省ける方式です。次の要件では、サービスごとの対応機能を確認します。発言の受信にはBotやイベント受信を検討し、流量超過には送信側の集約を優先します。
- ユーザーの発言やボタン操作を受け取りたい:Incoming Webhookの受信URL自体は投稿用だが、Slackでは投稿に含めたボタンの操作を別途Interactivityで受信できる。LINE WORKSは公式に「トークルームからのメッセージの送信には対応していません」と書き、Teams WorkflowsもMessageCardのボタンを動かさない。
- 投稿を後から更新・削除したい:SlackはWebhookの応答にメッセージの
tsが返らず、削除もできないと公式に書かれている。進捗を1通で書き換えたいならchat.postMessageとchat.updateを使う。Discordはwait=trueで返るIDから編集でき、Teamsはフロー側の「Update an adaptive card in a chat or channel」アクションで更新できる。 - 送信先を実行時に選びたい:Slack・LINE WORKSはURLに投稿先が紐づく。Teamsの紹介テンプレートも設定済みの宛先へ投稿するが、Workflowsでは後続アクションや分岐で送信先を選ぶ構成も作れる。宛先が増えてURLの発行・失効・権限管理の負担が大きくなる場合は、BotやAPIによる送信を検討する。
- 毎秒数件を超えて送りたい:Slackのチャンネル単位、Google Chatのスペース単位の毎秒1件は、Botにしても同じ投稿の枠にかかる。送信側でまとめる設計が先で、方式の変更では解決しない。
複数のチャットツールへ同じ通知を出すなら、送信を1か所に集めて本文の形だけ変えるほうが保守しやすくなります。社内システムと外部サービスの連携設計から相談したい場合は、API開発・システム連携の支援で受けています。
5サービスへ送り分けるPythonの共通関数
標準ライブラリだけで書いた送信関数です。本文の形をサービスごとに切り替え、429のときは Retry-After の秒数だけ待って再送します。Discordで403にならないよう、User-Agentを明示しています。存在しないURLへ送り、Slackで (404, 'no_team')、Discordで (404, '{"message": "Unknown Webhook", "code": 10015}') が返ることを確かめています。
import json
import os
import time
import urllib.error
import urllib.request
def build_payload(service, text):
if service == "slack":
return {"text": text}
if service == "discord":
if len(text) > 2000:
raise ValueError("Discord content exceeds 2000 characters")
return {"content": text}
if service == "google_chat":
return {"text": text}
if service == "lineworks":
return {"body": {"text": text}}
if service == "teams":
return {
"type": "message",
"attachments": [{
"contentUrl": None,
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [{"type": "TextBlock", "text": text, "wrap": True}],
},
}],
}
raise ValueError(service)
def notify(service, url, text, retries=3):
data = json.dumps(build_payload(service, text)).encode("utf-8")
req = urllib.request.Request(
url, data=data, headers={
"Content-Type": "application/json",
"User-Agent": "DiscordBot (https://example.com, 1.0)",
},
method="POST",
)
for _ in range(retries):
try:
with urllib.request.urlopen(req, timeout=10) as res:
return res.status, res.read().decode("utf-8", "replace")
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", "replace")
if e.code == 429:
time.sleep(float(e.headers.get("Retry-After", "1")))
continue
return e.code, body
return 429, "retry limit"
if __name__ == "__main__":
print(notify("slack", os.environ["WEBHOOK_URL"], "デプロイが完了しました"))
Discordの429は Retry-After ヘッダーに加えて本文の retry_after(小数の秒)でも待ち時間を返します。公式はヘッダーと本文のどちらでも待機時間を判断できるとしています。ヘッダーがない場合にも対応するなら、本文の値を使うフォールバックを追加します。
Webhook URLが漏れたときの対応と届かないときの切り分け
URLが漏れたら、最初に旧URLを無効化します。削除する場所はSlackがアプリ管理画面の「Incoming Webhooks」、Discordが「連携サービス」のウェブフック、Teamsがワークフロー一覧、Google Chatがスペースの「アプリとインテグレーション」です。通知を再開するなら新しいURLを発行してシークレットストアに入れ直し、古いURLがリポジトリの履歴に残っていないかも確かめてください。
通知が届かないときは、応答のステータスで原因の層を分けます。
| 応答 | 疑う箇所 |
|---|---|
| 404・403 | URL・権限・認証設定・User-Agent |
| 400 invalid_payload | JSONの構造・本文キー |
| 410 channel_is_archived | Slackの投稿先がアーカイブ済み |
| 429 | 送信上限の超過 |
| 2xxなのに表示されない | Discordのwait=false・Teamsの実行履歴 |
Teamsの場合は、ワークフローアプリの実行履歴に失敗が残ります。フローがオフになっていないか、所有者がアカウントを失っていないかを先に見てください。
よくある質問
Incoming Webhookの廃止はいつですか?
廃止されたのはMicrosoft TeamsのOffice 365コネクタ版で、2026年5月18日から22日にかけて無効化されました。後継はTeamsのワークフロー(Power Automate)です。Slack・Discord・Google Chat・LINE WORKSのIncoming Webhookは、2026年10月15日時点で提供が続いています。
SlackのIncoming Webhookは廃止されるのですか?
Slackアプリで発行するIncoming Webhookは現役です。移行を求められているのは、アプリを作らずに追加する旧来のカスタムインテグレーション版だけで、公式ドキュメントに停止日の記載はありません。移行するとJSONで channel や username を指定しても反映されなくなる点に注意してください。
Webhookは危険ですか?
URLだけで認証するIncoming Webhookでは、URLを知る第三者も投稿できます(Teams Workflowsは呼び出し元をテナント内ユーザーに限定する設定も可能)。漏れると業務チャンネルへ偽の通知やフィッシングのリンクを送り込まれます。URLをコードに直書きせず、公開リポジトリやチケットに貼らない、漏れたら削除して再発行する、の3点を守れば扱えるリスクです。
DiscordのWebhook URLはどこで確認できますか?
「サーバー設定」の「連携サービス」タブにある「ウェブフック」で、作成済みのWebhookを開き「ウェブフックURLをコピー」を押します。URLは https://discord.com/api/webhooks/ にWebhookのIDとトークンが続く形です。
SlackのWebhook URLはどこで確認できますか?
api.slack.com/apps で対象のアプリを開き、左メニューの「Incoming Webhooks」画面の下部「Webhook URLs for Your Workspace」に一覧が出ます。URLはチャンネルごとに1本ずつ発行されるので、投稿先のチャンネル名を見て選びます。