FlowKit

The Webhook node in n8n: the complete guide

Published 27 July 2026 · 8 min read

Almost every automation project eventually hits the same need: triggering an n8n workflow from the outside — a form on a website, a Stripe payment, an event in a SaaS tool, an internal script. That's exactly what the Webhook node does: it gives your workflow a public HTTP URL, and any system capable of sending a request can start it. Simple on the surface, this node nonetheless hides the pitfalls that fill the forums: a test URL that "stopped working", production returning 404, empty responses, duplicate processing. This guide covers the node end to end — how it works, test vs production, response options, reading incoming data, typical use cases, and best practices — with pointers to our in-depth guides on each advanced topic.

What the Webhook node is: an HTTP front door to your workflow

A webhook flips the usual integration logic. Instead of polling an API every five minutes to check whether something changed, the source system notifies you the moment the event happens, by sending an HTTP request to a URL you gave it. In n8n, the Webhook node is a trigger: placed at the start of a workflow, it generates that URL, listens for incoming requests, and starts an execution on every call, with the request data as the starting point.

The whole mechanism rests on the web's request/response model, formalized by Roy T. Fielding in his 2000 dissertation, Architectural Styles and the Design of Network-based Software Architectures (see it on Google Scholar) — the foundational work behind REST. It lays out the constraints that make webhooks so robust: stateless interactions, where every request carries everything needed to process it, and a uniform interface (URL + HTTP method + body) that any client knows how to speak. That's precisely what makes the Webhook node universal: Stripe, a CRM, a Python script, or a plain curl all use the same contract.

Test URL vs production URL: the number one source of confusion

Every Webhook node exposes two URLs, visible in the node panel, and they behave very differently.

The test URL (/webhook-test/...) only works during a manual execution. Concretely: you click Execute workflow in the editor, n8n starts listening, you send your request, the execution unfolds in front of you with the data visible node by node on the canvas — then the listener stops. Call the same URL two minutes later without restarting the listener, and nobody answers. It's a debugging tool, not a URL to hand to a third-party service.

The production URL (/webhook/...) is the opposite: it only exists once the workflow is activated (the Active toggle). It then listens continuously, every call triggers an execution, and those executions don't appear in the editor but in the workflow's executions list. Another important subtlety: it's the saved, activated version of the workflow that runs — if you edit the workflow without saving it again, production keeps running the old version.

Test URL (/webhook-test/) Production URL (/webhook/)
When it listens Only during a manual execution started from the editor Continuously, as soon as the workflow is active
Active workflow required No Yes
Where to see the data Directly on the canvas, node by node In the executions list
Version executed The one shown in the editor The last saved version of the active workflow
Purpose Debugging, development Real integrations (Stripe, forms, SaaS)

The reflex to build: a 404 on a webhook almost always means a workflow that isn't activated (production) or a listener that wasn't restarted (test).

HTTP methods, custom paths, and response options

Method and custom path

The node accepts the standard HTTP methods — GET, POST, PUT, DELETE, PATCH, among others — chosen according to what the calling system can send. Most services (Stripe, forms, SaaS tools) send POST with a JSON body; GET works fine for a simple trigger parameterized through the URL.

The path is customizable: instead of the default generated identifier, give it a readable name (/webhook/new-lead, /webhook/stripe-payments). It's more maintainable, but avoid guessable paths on sensitive workflows — an obscure path isn't a security measure, just a courtesy to your future self.

Respond immediately or at the end: the choice that changes everything

The node's Respond option determines what the caller receives:

  • Immediately — n8n replies as soon as the request arrives, before even running the rest of the workflow. The caller knows the request was received, without knowing the outcome. This is the right choice for event notifications (Stripe, SaaS), where the sender just wants a fast acknowledgment.
  • When Last Node Finishes — the response is sent when the workflow ends, with the last node's data. Handy for short, synchronous workflows.
  • Using 'Respond to Webhook' Node — you place a Respond to Webhook node in the workflow, at the exact point where the answer is ready, with full control over the HTTP status code, headers, and body. This is the most flexible mode: reply in JSON after a computation, return a 202 then keep processing, or send a clean 400 if the payload is invalid.

For long-running workflows — typically an AI agent that thinks for thirty seconds — responding at the end exposes the caller to a client-side timeout. Our dedicated guide on webhooks, timeouts, and AI agents walks through the asynchronous pattern: reply immediately with a task identifier, then deliver the result via callback or retrieval.

Reading the data: query, body, headers, files

The Webhook node structures the incoming request into three blocks directly accessible via expressions in the following nodes:

  • URL parameters{{ $json.query.source }} for a call to ...?source=landing.
  • JSON body{{ $json.body.email }} for a JSON POST containing an email field. Forms sent as application/x-www-form-urlencoded are parsed into body as well.
  • Headers{{ $json.headers["x-signature"] }} to read a signature or token. Careful: header names arrive lowercased.

For files, a multipart/form-data call makes the uploaded parts appear as binary data attached to the item, usable by downstream nodes like any n8n binary. If you expect heavy files, keep the instance's payload limits and binary storage mode in mind — and if the real need is a user-facing form with uploads, the Form Trigger is often a better fit than a bare webhook, with the form page included. Finally, a Raw Body option lets you receive the unparsed request body — essential for verifying an HMAC signature computed over the exact bytes of the request.

Typical use cases

External form or website. A custom form, a CMS, or a static site posts straight to the webhook: AI lead qualification, CRM entry, team notification. The same pattern powers an AI chat widget embedded on a website, where every visitor message goes to an n8n webhook that queries an agent.

SaaS notifications. Most tools (CRMs, helpdesks, e-signature tools, e-commerce platforms) can call a URL when an event happens: ticket created, document signed, order placed. The n8n webhook becomes the entry point of the entire processing chain.

Stripe and payments. The textbook case: Stripe notifies every event (successful payment, failure, dispute) via webhook. Our guide to Stripe + n8n for payment recovery shows how to turn those events into AI-driven dunning sequences.

Internal API. An n8n webhook can serve as a lightweight in-house API: an endpoint that receives a question and returns an answer generated by a RAG lookup, as in our RAG question-answering API workflow — that's exactly the architecture of the RAG Assistant Pack ($119), where the Webhook node and Respond to Webhook bracket the retrieval-and-generation chain.

Best practices for a production webhook

Secure it from day one. A production URL is public: without protection, anyone who finds it can trigger your workflow. The node offers built-in authentication (Basic Auth and Header Auth in particular), and serious services like Stripe sign their requests with HMAC, to be verified on the n8n side before any processing. Our guide to securing an n8n webhook covers both approaches step by step.

Plan for duplicates. Webhook senders retry when in doubt (timeout, 5xx), so the same event can arrive twice. If the workflow creates an invoice or sends an email, a duplicate is costly. The remedy is idempotency: detecting that an event was already processed and skipping it cleanly — the method is detailed in our guide to webhook idempotency.

Respond fast, process afterward. Many senders consider a webhook failed if it doesn't answer quickly, and then trigger their retries — a source of duplicates. For any processing beyond a few seconds (AI agents, RAG chains, document generation), respond immediately and process asynchronously, as detailed in the timeouts and AI agents guide.

Test locally with a tunnel. An n8n running on your machine isn't reachable by Stripe or an external SaaS. A tunnel (n8n's --tunnel option in development, or a dedicated tool) temporarily exposes the local instance on a public URL — the full walkthrough is in our guide to testing n8n webhooks locally.

Handle failures on both sides. Downstream of the webhook, outgoing calls deserve a real retry-and-timeout policy, and the whole workflow should be covered by an Error Workflow that alerts you when a webhook-triggered execution fails silently — because in production, nobody is watching the canvas.

The node to master before all the others

The Webhook node is arguably the most structuring trigger in n8n: it's what turns an automation instance into a real back-end capable of talking to the rest of your stack. Remember the essentials — the test URL only listens during a manual execution, production requires an activated workflow, the response mode should match the processing time, and security plus idempotency are not optional. Once those reflexes are in place, every satellite article around this guide (HMAC security, local testing, duplicates, timeouts) slots naturally into the same foundation.

FAQ

Frequently asked questions

Why does my n8n webhook return a 404 error in production?

The most common cause: the workflow isn't activated. The production URL (/webhook/...) is only registered once the workflow is toggled to Active. The other classic culprit: the call is hitting the test URL (/webhook-test/...) while nobody has clicked Execute workflow in the editor — the test URL only listens during a manual execution.

What's the difference between the test URL and the production URL of an n8n webhook?

The test URL (/webhook-test/...) only works during a manual execution started from the editor: it listens for one call, shows the received data directly on the canvas, then stops. The production URL (/webhook/...) listens continuously as soon as the workflow is activated, and its executions show up in the executions list, not in the editor.

How do I read the JSON body sent to an n8n webhook?

The Webhook node exposes the incoming request in a structured form: the JSON body is available via the expression {{ $json.body }}, URL parameters via {{ $json.query }}, and headers via {{ $json.headers }}. A POST containing an email field is therefore read simply with {{ $json.body.email }} in the following nodes.

How can an n8n webhook respond with a result computed by the workflow?

In the Webhook node's options, set Respond to Using 'Respond to Webhook' Node, then place a Respond to Webhook node at the point in the workflow where the response is ready. You then control the HTTP status code, headers, and body returned — essential for sending the result of an AI task or a RAG lookup back to the caller.

Bundle FlowKit Complet

€269