【2026年版】n8nでSlackボタン承認フローを作る方法|インタラクティブ返信で処理を分岐させる手順
Slack承認フロー、「なぜか動かない」で詰まっていませんか
Slackにボタン付きメッセージを送って、押したら次の処理へ——。シンプルに聞こえるこのフロー、実際に組もうとするとハマるポイントが3箇所ある。「Slack Triggerでボタンのイベントを受け取ろうとしたら何も飛んでこない」「Waitノードを置かなかったらフローが即終了した」「Self-hosted環境でHTTPで試したら登録すら弾かれた」。この記事ではその3つの罠を全部回避しながら、Slackボタン承認フローを一気通貫で組み上げる手順を説明する。
この記事を読むと、n8nでSlackボタン承認フローを「ゼロから動かすまで」が完全にわかる。
💡 関連教材: n8nノーコード自動化 実践ワークフロー集(¥1,980) — Gmail/Slack/Notion/Claude連携の動くワークフロー10本を実装込みで完全解説(全35ページ)
結論:必要なのはこの4つのノードの組み合わせ
先に答えを出す。Slackボタン承認フローに最低限必要なのは以下の4種類だ。
- Slackノード(Block KitボタンつきメッセージをPOST)
- Waitノード(Resume URLを発行してフローを「一時停止」する)
- Webhookノード(Slack AppのInteractivity URLとして登録し、ボタン押下Payloadを受け取る)
- Switchノード(
approved/rejectedなど値で分岐する)
この4つが揃って初めてフローが成立する。1つ欠けても動かない。順番に解説していく。
なぜSlack TriggerノードだけではボタンのPayloadを受け取れないのか
ここが一番誤解されている。
Slack Triggerが受け取れるイベントの範囲
n8nのSlack Triggerノードは、SlackのEvents API経由のイベントを受信する。具体的には「メッセージが投稿された」「チャンネルに参加した」といったイベントだ。
ボタン押下はこれとは別のAPIで動く。SlackのInteractivity(インタラクティブコンポーネント)は、Slack Appの設定画面の「Interactivity & Shortcuts」に登録した専用のURLにPOSTリクエストを送る仕組みになっている。Slack TriggerノードのURLとは全く別物だ。
つまり構造的に、ボタン押下のPayloadはWebhookノードでしか受け取れない。
Waitノードがない場合に何が起きるか
実際にやってみて驚いたのだが、WaitノードなしでSlackメッセージを送信するだけのフローを組むと、「メッセージを送信した瞬間にフローが完了扱いになる」。
ボタンをユーザーが押すのは数分後・数時間後かもしれない。その間フローを「生きたまま待機させる」ための仕組みがWaitノードだ。WaitノードはResume URLというエンドポイントを発行する。そのURLにHTTPリクエストが届いた瞬間、一時停止していたフローが再開する。
Waitノードの最大待機時間は1年まで設定できる。長期の稟議承認フローにも十分対応できる。
Cloud版とSelf-hosted版の違い
| 項目 | Cloud版 | Self-hosted版 |
|---|---|---|
| Webhook URL | 自動で固定HTTPS URLが発行される | 自分でドメイン・HTTPS設定が必要 |
| Interactivity登録 | そのままSlack Appに貼れる | ngrokやCloudflare Tunnelが必要(開発時) |
| Waitノードの動作 | そのまま動く | 同上、ただしWebhook URLと同じドメイン設定が必要 |
| 設定難易度 | ★☆☆ | ★★★ |
Self-hosted環境でローカル開発する場合、SlackはコールバックURLにHTTPS必須で、HTTPは登録時点で弾かれる。ngrokを使えばhttps://xxxxx.ngrok.ioのような一時URLを取得できるので、それをSlack Appに登録する。本番環境ではCloudflare TunnelかリバースプロキシでHTTPS化するのが現実的だ。
全体ワークフロー構成図と各ノードの役割
フロー全体像
[何らかのTrigger]
↓
[Slackノード:Block Kitボタン付きメッセージ送信]
↓
[Waitノード:Resume URL発行 → フロー一時停止]
↓ ← ここでユーザーがSlackのボタンを押す
[Webhookノード:ボタン押下Payloadを受信・フロー再開]
↓
[Switchノード:action_value で分岐]
↙ ↘
[承認処理] [却下処理]
↓ ↓
[Respond to Webhook:Slackにレスポンス返却]
各ノードの役割一覧
| ノード名 | 役割 | 注意点 |
|---|---|---|
| Slack(Send Message) | Block KitでボタンつきメッセージをPOST | blocksフィールドにJSON直書きする |
| Wait | Resume URLを発行してフローを一時停止 | URLをSlackメッセージのボタンURLに埋め込む |
| Webhook | Slack AppのInteractivity URLとして登録 | HTTPSであること、パスを固定で設定 |
| Switch | action_valueの値で条件分岐 |
Payloadのパスを正確に指定する |
| Respond to Webhook | Slackへ200レスポンスを3秒以内に返す | これがないとSlack側でエラー表示される |
SlackのInteractivityには3秒以内のレスポンスというタイムアウト仕様がある。重い処理はRespond to Webhookで先に200を返してから非同期で走らせる設計が鉄則だ。
ステップ別セットアップ手順
Step1:Slack AppにWebhook URLを登録する
- api.slack.com/apps にアクセスしてアプリを選択
- 左メニューの「Interactivity & Shortcuts」を開く
- InteractivityのトグルをONにする
- 「Request URL」フィールドに、n8nのWebhookノードのURLを貼る
- Cloud版例:
https://your-instance.app.n8n.cloud/webhook/slack-interaction - Self-hosted例:
https://your-domain.com/webhook/slack-interaction
- Cloud版例:
- 「Save Changes」をクリック
これでSlack上のボタンが押されるたびに、このURLにPOSTリクエストが飛んでくる。
Step2:n8nでWaitノードを設置しResume URLを取得する
Waitノードを配置したら、Resume URLの取得方法を確認する。
- Waitノードの設定画面で
Resume on webhook callを選択 $json["resumeUrl"]という変数にResume URLが格納される(実行時に動的生成)
このURLをSlackメッセージのボタンに直接埋め込む設計が最もシンプルだ。後述のBlock Kit JSONで使う。
Step3:Block Kit JSONでボタン付きメッセージを組む
Slackノード(Send Message)のBlocksフィールドに以下のJSONを設定する。{{ $json.resumeUrl }}の部分がWaitノードのResume URLを動的に挿入する箇所だ。
{ “blocks”: [ { “type”: “section”, “text”: { “type”: “mrkdwn”, “text”: “申請が届いています\n申請者: {{ $json.requester }}\n内容: {{ $json.content }}” } }, { “type”: “actions”, “elements”: [ { “type”: “button”, “text”: { “type”: “plain_text”, “text”: “✅ 承認する” }, “style”: “primary”, “value”: “approved”, “url”: “{{ $json.resumeUrl }}?action=approved” }, { “type”: “button”, “text”: { “type”: “plain_text”, “text”: “❌ 却下する” }, “style”: “danger”, “value”: “rejected”, “url”: “{{ $json.resumeUrl }}?action=rejected” } ] } ] }
ポイントは`url`フィールドにResume URLを設定している点だ。ボタンを押すとSlackがそのURLをブラウザで開く仕組みで、同時にWaitノードへのコールバックが発生してフローが再開する。クエリパラメータ`?action=approved`で承認か却下かを後続のSwitchノードに渡す。
### Step4:WebhookノードでInteractivity Payloadを受け取る
Webhookノードの設定は以下の通り。
```text
HTTP Method: POST
Path: slack-interaction
Authentication: None(Slack署名検証を別途実装する場合はHeaderで処理)
Response Mode: Using Respond to Webhook Node
SlackからのPayloadはapplication/x-www-form-urlencoded形式で飛んでくる。payloadというキーの中にJSON文字列が格納されているので、後続ノードでJSON.parse()するか、n8nのExpressionで{{ JSON.parse($json.payload) }}と書いてオブジェクトに変換する。
実際のPayload構造の主要部分はこうなっている。
{ “type”: “block_actions”, “actions”: [ { “type”: “button”, “action_id”: “button_approve”, “value”: “approved” } ], “response_url”: “https://hooks.slack.com/actions/xxx/yyy/zzz”, “user”: { “id”: “U12345678”, “name”: “yamada.taro” } }
`response_url`は後でメッセージを上書きするために使う。必ず保持しておく。
### Step5:Switchノードで承認・却下を分岐させる
Switchノードに以下の条件を設定する。
```text
値の参照先: {{ $json.query.action }}
条件1: approved → 承認フローへ
条件2: rejected → 却下フローへ
Default: エラーハンドリングへ
Step3のURLに?action=approvedを付けていたので、WebhookノードのQueryパラメータとしてactionが取得できる。
Step6:処理後にSlackのメッセージを上書きする
承認・却下の処理が終わったら、元のSlackメッセージを「承認済み」「却下済み」の表示に更新する。response_urlにPOSTするだけで実現できる。
// n8nのHTTP Requestノードの設定
// Method: POST
// URL: {{ $json.response_url }}
// Body(JSON):
{
"replace_original": true,
"text": "✅ この申請は承認されました(承認者: {{ $json.approver_name }})"
}
replace_original: trueにすると、元のボタン付きメッセージが上書きされる。承認済みなのにボタンが残り続けるのを防げる。
よくある失敗と正直なデメリット
失敗1:3秒タイムアウトでSlackにエラーが出る
Slackはボタン押下から3秒以内にHTTP 200を返さないと、Slack側でエラーメッセージを表示する。重い処理(DBへの書き込み、外部API呼び出し)をResponse前に置くと確実に詰まる。
対策はRespond to Webhookノードを一番最初に置いて空の200を返し、実処理を非同期に流す設計にすること。
失敗2:WaitノードのResume URLを間違えて別フローのURLを使う
WaitノードのResume URLは実行ごとに動的生成される。ハードコードすると古いURLを参照して永遠にフローが再開しない。必ず{{ $json.resumeUrl }}で動的に参照する。
失敗3:Self-hosted環境でPayloadが届かない
HTTP環境でSlack AppのInteractivity URLを設定しようとすると、Slackの設定保存画面でバリデーションエラーになる。ngrokを使う場合もセッションが切れると新しいURLになるので、開発中は頻繁に再登録が必要になる。正直かなり面倒だ。本番環境では専用ドメイン+Let’s EncryptのHTTPS設定を最初に固めてから開発を進めるほうが効率がいい。
このアーキテクチャの正直なデメリット
- WaitノードはCloud版の実行コストを消費する。長期待機フローを大量に走らせるとプランのクレジットに影響する
- Slack AppのInteractivity URL変更は即時反映されないことがある。設定後5〜10分待ってから動作確認するほうが安全
- ボタンのURL方式はモバイルSlackでの動作が不安定なケースがある。ブラウザが開く仕様のため、モバイルアプリでは体験が良くない。モバイル利用が多い場合はAction IDを使う本格的なInteractivity実装を検討する
よくある質問
Q1:承認フローで「誰が承認したか」を記録するには?
Webhookノードで受け取るPayloadのuserオブジェクトにidとnameが含まれている。$json.payloadをパースした後にactions[0].user.nameで取得できる。これをGoogle SheetsやNotionのデータベースに書き込むノードを分岐後に追加すればよい。
Q2:承認が必要なメッセージを複数人に同時送り、どちらかが押したら処理したい場合は?
WaitノードのResume URLは1度コールされたらフローが再開して無効化される。複数人に送る場合、「最初の1人が押した時点で処理を進める」仕様で問題ないならそのまま使える。一方、「全員の承認が必要」なケースはカウンターをDBに持つ設計が必要になる。n8n単体で完結させるのは難しく、外部DBとの組み合わせが現実的だ。
Q3:ボタンのURLをクリックするとブラウザが開いてしまうが、Slack内で完結させたいのは?
URL方式の仕様上、ブラウザが開くのは避けられない。Slack内のみで完結させたい場合はurlフィールドではなくaction_idを使い、Slack AppのSlash CommandやInteractivity経由でPOSTさせる設計に変更する必要がある。ただしその実装はより複雑になる。手軽さを優先するならURL方式を使い、Respondページを「承認済みです。このタブは閉じてください」と表示するだけのHTMLにする運用が現実的だ。
まとめ:次にやること、1つだけ
Slack承認フローで詰まる原因の9割は「Slack TriggerとWebhookノードの役割の混同」と「Waitノードの未設置」だ。この2点さえ押さえれば、あとは手順通りに組むだけで動く。
今すぐやること:n8nにWebhookノードを1つ追加して、パスをslack-interactionに設定し、そのURLをSlack AppのInteractivity & ShortcutsのRequest URLに登録する。
これだけでボタン受信の基盤が整う。Slackメッセージ送信の細かいBlock Kit設計については「n8n Slack通知カスタマイズ」の記事も合わせて読んでほしい。Block Kitのsectionやcontextブロックの使い方を詳しく扱っている。
関連記事
- n8n Slack通知カスタマイズ|Block Kit整形・ボタン設定手順2026
- n8n Gmail 自動返信|添付ファイル条件分岐で送信内容を変える手順2026
- n8n Webhook Notion 自動登録やり方|外部フォーム送信をDBに保存する手順2026
📘 もっと深く学びたい方へ
この記事で紹介した内容を、さらに体系的に・実務レベルで習得できる教材を販売中です。
n8nノーコード自動化 実践ワークフロー集(¥1,980)
Gmail/Slack/Notion/Claude連携の動くワークフロー10本を実装込みで完全解説(全35ページ)
- Cloud版前提・2026年最新のn8n v1系UI完全対応
- 動くノード設定値・JSON・OAuth設定まで全部入り
- 10ワークフロー(Gmail/Slack/Notion/Discord/Webhook/RSS)はコピペで即実務投入
👉 今すぐ購入する
ChatGPT業務自動化 実践テンプレート集(¥1,480)
API・スプレッドシート・メール・議事録・請求書をコピペで自動化する実装特化型テンプレート集(全22ページ)
- 動くGASコード・API設定手順・プロンプトをワンセット収録
- スプレッドシート連携/メール/議事録/請求書を実務レベルで自動化
- コピペで即動く実装コード(Python / GAS)付き
👉 今すぐ購入する
関連ツール紹介
AIスキルを収益化するなら → ココナラでサービスを出品できる。AIライティング・画像生成・データ分析など、AIスキルを活かした案件の需要は増えている。![]()
おすすめツールの一覧はこちらにまとめている。