初心者向け
n8n Webhookノードの使い方:URLが2つある理由と、テストで詰まる場所
Webhookノードには Test URL と Production URL があり、有効になる条件が違います。404になる3つのパターン、テスト用ボタンが2つあって実行範囲が変わること、届くデータの形を実際に叩いて確かめました。
公開
動作確認: — n8n 2.36.8 / Webhook ノード v2.1
Webhook ノードは、外部から n8n を呼び出すための受け口です。 フォームの送信、決済の完了、GitHub のプッシュ。そういった「向こうから来る」きっかけで ワークフローを動かすときに使います。
設定項目は少ないのに、動かなくて詰まることが多いノードでもあります。 理由ははっきりしていて、URLが2種類あり、それぞれ有効になる条件が違うからです。
実際に叩いて確かめた内容をまとめます。
URLが2つある
ノードを開くと、上に Webhook URLs という欄があり、Test URL と Production URL の 切り替えタブが出ます。


見た目はよく似ていますが、パスが違います。
| Test URL | Production URL | |
|---|---|---|
| パス | /webhook-test/<Path> |
/webhook/<Path> |
| 有効になる条件 | ボタンを押して待機状態にしたとき | Publish 済みのとき |
| 使える回数 | 1回だけ | 何度でも |
| 画面での見え方 | キャンバスにデータが流れる | キャンバスには出ない(実行履歴にだけ残る) |
Publish しても Test URL は有効になりません。 逆に、待機状態にしても Production URL が有効になるわけでもありません。この2つは完全に別系統です。
404になる3つのパターン
叩いて404が返るとき、n8n はどれに該当するかを教えてくれます。
1. Publish していないのに Production URL を叩いた
{
"code": 404,
"message": "The requested webhook \"POST hook-probe\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. ...
Note that unlike test URL calls, production URL calls aren't shown on the canvas
(only in the executions list)"
}
2. 待機状態にしていないのに Test URL を叩いた
{
"hint": "Click the 'Execute workflow' button on the canvas, then try again.
(In test mode, the webhook only works for one call after you click this button)"
}
3. メソッドが違う
{
"message": "This webhook is not registered for GET requests.
Did you mean to make a POST request?"
}
HTTP Method を POST にしてあるのに GET で叩くと、これが返ります。
パスが合っていても404になるので、URLばかり見ていると気づきません。
テスト用のボタンが2つあり、動く範囲が違う
ここが一番はまりました。
Test URL を有効にするボタンは、2箇所にあります。
- ノードを開いた中にある Listen for test event
- キャンバスの下にある Execute workflow
どちらを押しても Test URL は有効になります。ただし、動く範囲が違いました。
同じ Test URL を、同じ内容で叩いた結果です。
| 押したボタン | 実行された範囲 | 返ってきた応答 |
|---|---|---|
| Listen for test event(ノード内) | Webhookノードだけ | 空・200 |
| Execute workflow(キャンバス) | ワークフロー全体 | 201 + {"ok":true,...} |
ノード内のボタンで実行したときの記録を見ると、こうなっていました。
"startData": { "destinationNode": { "nodeName": "受け口", "mode": "inclusive" } },
"lastNodeExecuted": "受け口"
そのノードまでで止める指定が入っています。 後続のノードには実行記録が1つもありません。
つまり Listen for test event は「このノードに何が届くか」を見るためのもので、 ワークフロー全体の動作確認には使えません。応答が空で返ってきたら、 設定ミスではなく押したボタンを疑ってください。
n8n のエラーメッセージが案内しているのも Execute workflow の方です。
届くデータの形
Production URL に、クエリとカスタムヘッダーを付けて叩いた結果です。
{
"headers": {
"host": "localhost:5678",
"user-agent": "curl/8.21.0",
"content-type": "application/json; charset=utf-8",
"x-custom-header": "hello"
},
"params": {},
"query": { "name": "takuma", "n": "3" },
"body": {},
"webhookUrl": "http://localhost:5678/webhook/hook-probe",
"executionMode": "production"
}
後続のノードでは $json.body.〇〇 や $json.query.〇〇 で取り出します。
気をつける点が3つあります。
ヘッダー名は小文字になります。 X-Custom-Header を送っても、届くのは
x-custom-header です。$json.headers['X-Custom-Header'] と書くと undefined になります。
executionMode でテストか本番かを判別できます。 Test URL 経由なら test、
Production URL 経由なら production でした。テストのときだけ通知を飛ばさない、
といった分岐に使えます。
params はパスに : を使ったときに入ります。 Path を order/:id のように
書いた場合です。普通のパスなら空のままです。
クエリは文字列、ボディは型が残る
これは実務で効きます。
?n=3 を送ると、query.n は "3"(文字列) になります。一方、
POST で {"count": 5} を送ると、body.count は 5(数値) のままです。
"query": { "n": "3" }, // 文字列
"body": { "count": 5 } // 数値
クエリ文字列にはもともと型が無いので当然ではあるのですが、混ざると事故ります。
n8n の比較は型に厳しく、1 と '1' は別物として扱われます
(Merge ノードの記事で実際に一致しなくなった例を書きました)。
クエリで受けた値を数値として使うなら、明示的に変換してください。
応答の返し方は4つある
Respond で、呼び出し元に何をいつ返すかを決めます。

| 表記 | 何が返るか | 実測 |
|---|---|---|
| Immediately(既定) | 受け付けた時点で即返す | {"message":"Workflow was started"} / 200 |
| When Last Node Finishes | 最後のノードの出力 | 1件目だけ / 200 |
| Using ‘Respond to Webhook’ Node | 別ノードで組み立てた内容 | 自由・ステータスも指定可 |
| Streaming | 対応ノードからリアルタイムに返す | 未検証 |
When Last Node Finishes で返るのは1件目だけでした。
最後のノードが2件出力していても、応答に入ったのは1件目のみです。
全部返したいなら Respond to Webhook を使うことになります。
Respond to Webhook で応答を組み立てる
Respond を Using ‘Respond to Webhook’ Node にして、Respond to Webhook ノードを
フローの中に置きます。

Respond With で返す形を選びます。

- All Incoming Items — 入力の全アイテムを返す
- First Incoming Item — 1件目だけ(既定)
- JSON — 自分で組み立てたJSONを返す
- ほかに Binary File / JWT Token / No Data など
JSON を選び、Response Body に式を入れて、Options から Response Code を
201 にしたところ、そのとおり 201 が返りました。
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
{"ok":true,"受け取った件数":2}
このノードには注意書きが出ています。
When using expressions, note that this node will only run for the first item in the input data
式を使う場合、このノードは1件目に対してしか動きません。
件数を数えるような処理は $input.all().length のように書く必要があります。
検証していないこと
Streamingは試していません。 対応ノードが必要なため、確認できていませんAuthenticationはNoneのままで検証しました。Basic / Header / JWT は未確認です- 外部からのアクセスは試していません。 すべて
localhostからの呼び出しです。 インターネット経由で受ける場合の公開方法(トンネル、リバースプロキシ)には触れていません params(Pathに:を使う形)は実際に叩いていません。 空だったことを 確認しただけです- 日本語のボディを送る検証で一度文字化けしましたが、原因は私の送信側のツールが UTF-8 で送っていなかったことでした。UTF-8 で送り直したら正常に届いています。 n8n の挙動ではありません
Webhook は「設定は合っているのに動かない」が起きやすいノードですが、 原因はURLの種類・Publish の有無・メソッド・押したボタンのどれかに収まりました。
- Publish と本番実行の違いは n8n 用語集 に
- 本番実行でしか動かないものは他にもあります。n8n のエラー通知は、手動実行では飛ばない
- こちらから外部APIを叩く側は HTTP Request ノードの使い方