Slack APIは1つのAPIではありません。アプリからSlackへ命令を送るWeb APIと、Slackで起きた出来事をアプリへ届けるEvents APIという、向きの違う仕組みの集まりです。この記事では、2つの通信の向きを軸に全体像を整理したうえで、xoxb・xoxp・xappのトークンの違いと権限スコープの絞り方、HTTPとSocket Modeの選び分け、3秒以内の応答と署名検証を解説します。後半ではBolt for Pythonでボタン付きの承認フローを動かすコードまで載せました。数値と仕様は2026年10月時点の公式ドキュメントに基づきます。
まとめ:Slack APIで最初に決める受信方式とトークンの種類と配布形態
Slack APIの実装で先に決めることは3つではなく、実質2つです。1つはSlackからイベントを受け取る経路で、公開URLを用意できるならHTTP、社内ネットワークの内側で動かすならSocket Modeを選びます。Socket Modeのアプリは公開Marketplaceに載せられないため、社外へ配布する予定があるならこの時点でHTTPに決まります。
もう1つはトークンです。ボットとして投稿・取得するならxoxbのボットトークン、利用者本人の権限で操作するならxoxpのユーザートークン、Socket Modeの接続にはxappのアプリレベルトークンを使います。スコープは使うメソッドから逆算し、App Manifestに宣言して差分をレビューできる形にしておきます。
見落としやすいのはレート制限です。投稿は1チャンネルあたり毎秒1件、履歴取得は社外へ商用配布するMarketplace未承認アプリだと毎分1回まで絞られます。通知を送るだけならWebhookで足ります。双方向のやり取りや承認フローが必要になった段階でSlack APIを自作する、という順番で検討してください。
Slack APIを構成するWeb APIとEvents APIの役割と通信の向き
Slack APIの解説が分かりにくくなる原因は、命令と通知という逆向きの仕組みを同じ名前で呼んでいる点にあります。まず向きで分け、そのうえでBoltなどのSDKがどこを肩代わりするかを見ていきます。
Web APIはslack.comのメソッドへトークン付きで送る命令の窓口
Slack Web APIの公式ドキュメントによると、Web APIは https://slack.com/api/ にメソッド名を続けたURLへHTTPで要求を送る形式です。投稿は chat.postMessage、履歴の取得は conversations.history、ユーザー情報は users.info というように、操作ごとにメソッドが分かれています。
認証はトークンを Authorization: Bearer ヘッダに載せる方式が推奨されています。応答の形式は必ずJSONで、成否を示すのは ok の真偽値です。HTTPステータスが200でも ok がfalseのことがあるため、エラー処理は error の文字列で分岐させます。
Events APIと対話操作がSlack側の出来事をアプリへ届ける仕組み
逆向きの通信を担うのがEvents APIです。メンションされた、チャンネルに投稿があった、といった出来事をSlackがアプリへ送ってきます。ボタンやモーダルの操作も同じ方向で、こちらはInteractivityという別の設定で受け取ります。
受け取り口は2通りあります。アプリ側に公開したRequest URLへHTTPで届けてもらう方式と、アプリからSlackへWebSocketをつなぎに行くSocket Modeです。どちらを選んでも、届いた出来事に対して投稿や更新をするときはWeb APIを呼びます。つまり双方向のアプリは、受信にEvents API、送信にWeb APIという組み合わせで成り立っています。
Webhook・ワークフロー・Bolt自作を要件で選び分ける比較表
Slackとつなぐ方法はSlack APIの自作だけではありません。要件ごとに下表で振り分けると、作らなくてよいものを作らずに済みます。
| 方式 | 向き | 向いている要件 | できないこと |
|---|---|---|---|
| Incoming Webhook | 外部からSlackへ | 監視やCIの通知 | 投稿の更新・返信 |
| ワークフロービルダー | Slack内で完結 | 定型の申請フォーム | 社内DBとの複雑な連携 |
| Web APIの直接呼び出し | 外部からSlackへ | 投稿の更新や履歴の取得 | イベントの受信 |
| Boltで作るアプリ | 双方向 | 承認フローや対話型のbot | サーバーの運用は自前 |
通知だけならWebhookで十分です。URL発行から整形までの実装はSlack Incoming Webhookの実装手順で扱っています。Boltは公式のSDKで、Python・JavaScript・Java向けに提供され、イベントの受信とWeb APIの呼び出しを同じコードの中で書けます。
xoxb・xoxp・xappのトークンと権限スコープを最小に絞る設計
Slack APIで起きる事故の多くは、コードよりもトークンとスコープの選び方から始まります。種類ごとの用途を押さえ、スコープを設定ファイルで管理する方法までを見ます。
ボット・ユーザー・アプリレベルの3トークンの用途と取り違え事故
Tokensの公式ドキュメントでは、接頭辞でトークンの種類が分かれています。xoxb- は、インストールされたアプリのボットとして動くためのボットトークンです。xoxp- はユーザートークンで、インストールした利用者本人の代わりに操作します。xapp- はアプリレベルトークンで、Socket Modeの接続のようにアプリ全体に関わる操作に使います。
よくある取り違えは、手軽だからとユーザートークンで投稿処理を作るケースです。投稿者が個人名になるうえ、その人が退職してアカウントが止まるとアプリも止まります。業務システムからの投稿はボットトークンを基本にしてください。トークンのローテーションは任意で有効にできますが、公式ドキュメントは一度有効にすると無効に戻せないと明記しています。更新処理を実装してから有効にする順番を守ります。
App Manifestでスコープを宣言しレビューできる形で管理する方法
スコープを管理画面で1つずつ足していくと、何のために付けた権限かが後から分からなくなります。App manifest referenceの形式でYAMLに書き、リポジトリで差分を見られるようにしておくのが安全です。次の例は、メンションを受けてボタン付きメッセージを投稿する承認botに必要な最小構成です。
display_information:
name: approval-bot
features:
bot_user:
display_name: approval-bot
always_online: false
oauth_config:
scopes:
bot:
- app_mentions:read
- chat:write
settings:
event_subscriptions:
bot_events:
- app_mention
interactivity:
is_enabled: true
org_deploy_enabled: false
socket_mode_enabled: true
ボットのスコープは app_mentions:read と chat:write の2つだけです。履歴を読む要件が出たら channels:history を足す、というように機能追加とスコープ追加を同じプルリクエストに入れると、権限が増えた理由がレビューの記録に残ります。
curlとBolt for Pythonで動かすSlack APIの最小実装と起動手順
ここからは実際に動かします。最初にcurlでWeb API単体の疎通を確かめ、次にBoltでイベントを受けるアプリを起動する順に進めると、トークンの問題とコードの問題を切り分けられます。
chat.postMessageをcurlで呼びokとtsを確認する疎通の手順
ボットトークンを環境変数に入れ、chat.postMessageを直接呼びます。送信先はチャンネル名ではなく、Cから始まるチャンネルIDで指定してください。名前は変更される可能性があるためです。
export SLACK_BOT_TOKEN="xoxb-your-bot-token"
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-type: application/json; charset=utf-8" \
--data '{"channel": "C0123456789", "text": "Slack APIからの疎通確認です"}'
成功すると "ok": true と、投稿を特定する ts が返ります。not_in_channel が返ったらボットをチャンネルへ招待し、missing_scope ならスコープを足して再インストールしてください。この ts を保存しておくと、あとで chat.update による書き換えやスレッド返信ができます。
Socket ModeでBoltアプリを起動するまでのトークン設定と順序
Bolt for PythonのREADMEの手順では、Socket Modeで動かすときに環境変数 SLACK_BOT_TOKEN と SLACK_APP_TOKEN の2つを使います。PyPIの slack-bolt は2026年10月22日時点で1.30系が最新で、対応するPythonは3.7以上です。
- 管理画面のBasic Informationでアプリレベルトークンを作り、スコープに
connections:writeを付ける - Socket Modeを有効にし、Event Subscriptionsで
app_mentionを購読する - アプリをワークスペースへインストールし、表示されたボットトークンを控える
pip install slack_boltを実行し、2つのトークンを環境変数に設定して起動する
Socket Modeの場合、READMEは署名シークレットもngrokのような外部公開の仕組みも不要だと説明しています。ローカルPCで試せるため、検証段階ではこの方式から入るのが手早い進め方です。
HTTPとSocket Modeの選び分けと3秒以内の応答と署名検証の実装
受信方式は後から切り替えられますが、運用設計は大きく変わります。公式ドキュメントの制約を並べて、どちらを本番に使うかを決めます。
公開URLとMarketplace掲載の可否で選ぶHTTPとSocket Modeの方式
Using Socket Modeによると、Socket Modeは公開HTTPのRequest URLを持たずにEvents APIと対話操作を使える方式です。同時に開けるWebSocket接続は最大10本で、接続は数時間ごとに更新されるため再接続の処理が要ります。そして公開Marketplaceには載せられません。
判断は単純です。社内専用のアプリでファイアウォールの外にURLを公開したくないならSocket Mode。複数の会社へ配布する、または負荷分散装置の後ろで台数を増やしたいならHTTPを選びます。Comparing HTTP and Socket Modeのとおり、両者はアプリの設定画面でいつでも切り替えられるので、検証はSocket Mode、配布前にHTTPへ移す段取りでも問題ありません。
3秒以内のack・最大3回の再送・署名検証を前提にした受信設計
Events APIは、受信から3秒以内に2xxを返さないと配信失敗として扱います。失敗すると最大3回、ほぼ即時・1分後・5分後に再送され、試行番号が付くのは x-slack-retry-num ヘッダです。重い処理を同期で走らせると再送で同じイベントを3回処理するため、先に応答を返してから非同期で処理し、イベントIDで重複を弾く設計にします。60分間に配信の95%超が失敗すると購読が一時停止される点も覚えておいてください。
HTTP方式では署名検証が必須です。v0:タイムスタンプ:生のリクエスト本文 を署名シークレットでHMAC-SHA256にかけ、比較対象は X-Slack-Signature です。5分以上ずれたタイムスタンプは再送攻撃として破棄します。受信側の冪等性の作り方はWebhookの実装方法と作り方でも整理しています。
ボタン付きメッセージで承認フローを組むBolt実装と期限の制約
Slack APIを自作する理由として多いのが、社内システムの申請をSlack上で承認させる仕組みです。ボタンの押下を受けて結果を書き換えるまでを、1つのファイルで動く形で示します。
block_actionsを受けてackしchat.updateで結果を書き換える実装
メンションを受けたら承認と差し戻しのボタンを出し、押されたら同じメッセージを結果で上書きします。Boltでは ack() を最初に呼ぶことで3秒の期限を満たします。
import os
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
app = App(token=os.environ["SLACK_BOT_TOKEN"])
def button(label, action_id, style):
return {"type": "button", "action_id": action_id, "style": style,
"text": {"type": "plain_text", "text": label}}
@app.event("app_mention")
def ask_approval(event, say):
say(text="承認依頼が届きました",
blocks=[
{"type": "section",
"text": {"type": "mrkdwn", "text": f"<@{event['user']}> さんから承認依頼です"}},
{"type": "actions",
"elements": [button("承認", "approve", "primary"),
button("差し戻し", "reject", "danger")]},
])
def close_request(body, client, result):
client.chat_update(channel=body["channel"]["id"], ts=body["message"]["ts"],
text=f"<@{body['user']['id']}> さんが{result}しました", blocks=[])
@app.action("approve")
def on_approve(ack, body, client):
ack()
close_request(body, client, "承認")
@app.action("reject")
def on_reject(ack, body, client):
ack()
close_request(body, client, "差し戻し")
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
ボタンを押した人のIDは body["user"]["id"] で取れます。実運用では、ここで社内システムの承認APIを呼び、承認権限を持つ人かどうかを照合してから書き換えてください。Slack上で誰でも押せる状態のままでは、承認の証跡として扱えません。
response_urlの30分5回とtrigger_idの3秒失効が効いてくる場面
Handling user interactionには、対話操作の期限が3つ書かれています。HTTP 200の応答は受信から3秒以内。ペイロードに含まれる response_url へは30分以内に最大5回まで返信できます。モーダルを開くための trigger_id は3秒で失効し、1回しか使えません。
効いてくるのは、承認の前に社内システムへ問い合わせて確認画面を出す場面です。問い合わせに3秒以上かかると trigger_id が切れてモーダルが開きません。先にモーダルを読み込み中の状態で開き、結果が返ってから views.update で中身を差し替える順番にします。スラッシュコマンドから起動する場合も同じ3秒の制約があり、スラッシュコマンドとは?Slackでカスタムコマンドを自作する手順と3秒ルールで詳しく扱っています。
Slack APIを自作すべき場面と見送る場面のレート制限込みの判断基準
作れることと、作るべきことは別です。レート制限の変更と運用の負担を踏まえて、自作に進む線を引きます。
conversations.historyの毎分1回制限が配布形態で効く2025年の変更
Rate limitsでは、Web APIのメソッドがTier 1の毎分1回以上からTier 4の毎分100回以上まで段階分けされ、超えるとHTTP 429と待つ秒数を示す Retry-After が返ります。投稿の chat.postMessage は1チャンネルあたり毎秒1件が目安です。
注意したいのは2025年5月29日の変更です。公式のchangelogによると、Marketplace外で商用配布するアプリは、conversations.historyと conversations.replies が毎分1回、1回あたり15件までに絞られました。社内で作って社内で使うアプリは対象外で、従来どおり毎分50回以上・1回1,000件のままです。社外向けに履歴を集計するサービスを作るなら、Marketplace承認を前提に計画しないと成り立ちません。
自作を見送りWebhookや既製アプリで済ませる要件の線引き
自作を見送ってよいのは、通知が一方向で済む場合、定型の申請がワークフロービルダーで閉じる場合、既製のSaaS連携アプリで要件を満たせる場合です。この3つのどれかに当てはまるなら、サーバーを運用してまでBoltアプリを持つ理由はありません。生成AIからSlackを操作したいだけなら、Slack MCPサーバーの接続手順と権限設計のように既存のサーバーをつなぐ方法もあります。
逆に、社内DBの値で承認者を決める、承認結果を基幹システムへ書き戻す、監査のために誰がいつ押したかを残す、といった要件が1つでもあれば自作の領域です。3秒の応答期限・再送時の重複排除・トークンの保管まで含めて設計できる体制が社内に無い場合は、API開発・システム連携の支援を入れて連携部分だけを切り出す方法もあります。
よくある質問
Slack APIを使い始めるときに出やすい疑問を、公式ドキュメントの記述に沿ってまとめます。
Slack APIで過去のメッセージを取得できますか?
取得できます。conversations.history でチャンネルの投稿を、conversations.replies で読み取れるのはスレッドの返信です。公開チャンネルなら channels:history、プライベートチャンネルなら groups:history のスコープが要り、ボットがそのチャンネルに参加している必要があります。Marketplace外で商用配布するアプリは毎分1回・15件の制限を受けるため、大量の履歴取得は社内アプリとして作るのが前提です。
ボットトークンとユーザートークンはどちらを使うべきですか?
業務システムからの投稿や取得はボットトークン(xoxb)を使ってください。ボットとして動くため、担当者の異動や退職でアカウントが止まってもアプリは動き続けます。ユーザートークン(xoxp)が必要なのは、本人の名前で投稿したい、本人だけが見える情報を読みたい、といった場面だけです。権限が個人に紐づく分、漏洩時の影響も大きくなります。
Socket Modeは本番運用に使えますか?
社内専用のアプリなら本番でも使えます。公開URLが要らないため、ファイアウォールの内側から動かせる点が利点です。ただし公開Marketplaceには載せられず、接続は数時間ごとに更新されるので再接続の処理が要ります。Boltの SocketModeHandler は再接続を内部で処理しますが、複数の会社へ配布する予定があるならHTTP方式で作ってください。
Slack APIのレート制限を超えるとどうなりますか?
HTTP 429が返り、Retry-After ヘッダに待つべき秒数が入ります。その秒数だけ待ってから再送すれば処理は続けられます。制限はメソッドとワークスペースの組み合わせごとに数えられるため、別のメソッドの呼び出しは影響を受けません。投稿を大量に送る処理では、1チャンネル毎秒1件を超えないよう送信側で間隔を空けておくと429自体を避けられます。
Incoming WebhookとSlack APIは何が違いますか?
Incoming Webhookは、発行されたURLへJSONを送るだけで1つのチャンネルに投稿できる送信専用の仕組みです。トークンもスコープも不要ですが、投稿の書き換えやイベントの受信はできません。Slack APIはトークンで認証し、投稿・更新・履歴取得・イベント受信まで扱えます。通知だけならWebhook、双方向のやり取りが要るならSlack APIと考えてください。
関連記事
- Incoming Webhookとは?Slack・Discord・Teams・Google Chatの使い方と違い:Webhookという仕組みそのものの入門と各ツールでの発行手順
- Webhookとは?読み方・仕組み・APIとの違い:APIとWebhookの違いをHTTPリクエストで確かめる基礎編
- Slack Codeとは?コードチャンネルの仕組みと組み込み手順:Slack上からコーディングエージェントを呼ぶ機能と権限設計
- Claude Tagとは?Slackで@Claudeに仕事を任せる新機能:既製のAIアプリをSlackへ組み込む場合の選択肢
- ChatGPT workspace agentsとは?API起動・Slack連携・権限設計:エージェントをSlackから起動する構成と権限の考え方