The Respond to Webhook node lets a workflow decide what the HTTP caller receives — body, status code, and headers — instead of n8n returning a generic acknowledgement. It only works if the Webhook node is first set to respond using the Respond to Webhook node, and that one setting is the reason most people think the node is broken.
The behaviour without it is quietly reasonable and quietly useless: the Webhook node answers immediately with a standard message and a 200, the workflow carries on in the background, and the caller learns nothing about whether anything worked. That is exactly right for a fire-and-forget notification and exactly wrong for anything the caller needs an answer from.
Table of contents
- The setup, in order
- Choosing what to respond with
- Validation and error responses
- The timeout, and long-running work
- Testing and the two URLs
- When you do not need this node at all
- How this fits the rest of the stack
- FAQ
The setup, in order
- Add a Webhook node as the workflow’s trigger.
- In that Webhook node, set Respond to Using ‘Respond to Webhook’ node. This is the step people skip.
- Add the Respond to Webhook node somewhere in the workflow. If it should return data produced by other nodes, place it after them.
- Configure Respond With to choose what goes in the body.
Skipping step two is the single most common cause of the node appearing to do nothing. The Webhook node keeps its default behaviour, replies immediately, and by the time your Respond node executes the HTTP conversation is already over. n8n ignores the node rather than erroring, so there is nothing in the log to point at.
The documented rules for what happens are worth memorising because each one explains a confusing case:
- The workflow finishes without reaching the Respond node — n8n returns a standard message with a 200 status.
- A second Respond node executes after the first — the workflow ignores it. Only the first one counts.
- A Respond node executes when there was no webhook — it is ignored entirely, which is why testing it from a Schedule trigger shows nothing.
Choosing what to respond with
The Respond With option covers the useful cases:
- All Incoming Items or First Incoming Item — return the data flowing into the node. There is a Put Response in Field option for these, which wraps the data under a field name you choose.
- JSON — compose the body yourself with an expression. The most common choice for an API-shaped endpoint, because it lets you return a stable contract rather than whatever your internal nodes happen to hold.
- Text — a plain string.
- Binary — return a file. Useful for generating a document and handing it straight back.
- No Data — an empty body with whatever status code you set.
Under node options there is a Response Code field. Use it. Returning 200 for a validation failure is the kind of thing that works fine until the caller is somebody else’s system, which reasonably assumes 200 means it worked.
{
"status": "accepted",
"id": "{{ $json.recordId }}",
"received": "{{ $now.toISO() }}"
}
One more behaviour worth knowing: the Respond node runs once, using the first incoming data item. If several items reach it, it does not respond several times — there is only one HTTP response to give.
Validation and error responses
The pattern that turns a webhook into a usable endpoint: check the input first, respond with a real status code, and only then do the work.
Webhook (Respond: Using Respond to Webhook node)
-> If (required fields present?)
true -> ...do the work... -> Respond to Webhook (200, result)
false -> Respond to Webhook (400, error message)
Two Respond nodes on different branches is fine, because only one branch executes. Two on the same path is not — the second is ignored.
For a webhook receiving traffic from a third-party service, the status code is part of the contract in a way that matters. Many services retry on 5xx and give up on 4xx. Returning 500 for a permanently malformed payload means the sender retries it forever; returning 400 tells it not to bother. Getting this backwards produces an endpoint that either loses data or receives the same broken record every five minutes for a week.
Add a secret check as the first branch. A webhook URL is effectively public, so verify a shared token in a header or validate a signature before doing anything else, and return 401 when it fails.
The timeout, and long-running work
The most-reported problem with this node is a request that hangs and then times out — often at around two minutes — with no response ever arriving.
The cause is structural rather than a bug. The HTTP caller holds the connection open waiting for your Respond node. If the workflow does five minutes of work first, the caller has usually given up long before, and intermediate proxies enforce their own limits regardless of what n8n does.
The fix is to stop making the caller wait:
Webhook -> Respond to Webhook (202 Accepted, {"status":"queued"})
-> ...the long work continues after responding...
Put the Respond node early — right after validation — and let the rest of the workflow run after it. The caller gets an immediate 202, the work happens, and nothing times out. This is the standard shape for any webhook doing more than a couple of seconds of work, and it is worth adopting by default rather than after the first timeout.
If the caller genuinely needs the result, give it a way to collect: return an ID in the 202 response and provide a second endpoint to poll, or call the caller back on a webhook of their own. Both are more work than responding synchronously and both actually function under load.
Testing and the two URLs
The Webhook node has a test URL and a production URL, and they behave differently in a way that catches everyone once.
- Test URL only listens while you have clicked Listen for test event in the editor. One request, then it stops.
- Production URL works whenever the workflow is active, and only when it is active.
A test that worked and a production URL that 404s is almost always a workflow that was never activated. Conversely, a production URL that has stopped responding usually means someone deactivated the workflow while editing.
curl -i -X POST https://n8n.example.com/webhook/your-path \
-H 'Content-Type: application/json' \
-H 'X-Webhook-Token: your-secret' \
-d '{"name":"test","amount":100}'
Use -i so you see the status code and headers rather than just the body. Half the things worth checking about a webhook response are in the headers.
There is also a setting that gives the Respond node a second output carrying the data it sent, which is off by default. Turning it on makes it much easier to see in the execution log exactly what the caller received — otherwise the node shows its input rather than its response, which is a documented behaviour and a persistent source of confusion.
When you do not need this node at all
Worth saying plainly, because reaching for it reflexively adds complexity.
- Fire-and-forget notifications. A service telling you something happened does not care what you say back. The default immediate 200 is correct and simpler.
- Internal triggers. A workflow you call from another workflow has better mechanisms than HTTP.
- Anything where the caller ignores the response. Many webhook senders do.
Use it when the caller is a form expecting a confirmation, a system that branches on your status code, a user-facing integration, or anything where returning a body is the point. Otherwise the default is one less node to maintain.
How this fits the rest of the stack
A webhook endpoint is only as available as the thing hosting it — a caller that gets a connection error usually does not retry, and the event is simply gone. That makes the runtime question the important one: a stable URL, a valid certificate, restart on failure, and execution history stored somewhere that survives a restart. n8n is one of the managed tools on RunxBuild, deployed with a live route, custom domains, environment variables, autoscaling, and logs per execution, with a managed Postgres beside it for history. Services on RunxBuild covers the deploy and log model, and the RunxBuild hosting calculator prices the tool, the database, storage, and bandwidth as separate lines so the whole automation stack is visible.
Useful related references:
- n8n AI Agent Node: What It Does and When a Plain Chain Is Better
- n8n + Qdrant: A Vector Search Node for Real Workflows
- n8n HTTP Request Node: The Auth and Error Playbook
- Node services on RunxBuild
FAQ
Why is my n8n Respond to Webhook node not working?
The Webhook node almost certainly still has its default Respond setting. Open it and set Respond to Using ‘Respond to Webhook’ node. Without that, the Webhook node answers immediately and n8n ignores your Respond node without raising an error.
Can I have more than one Respond to Webhook node?
Yes, on different branches of an If node, since only one branch executes. On the same path the second one is ignored — n8n only sends one HTTP response, and the first Respond node to execute wins.
Why does my n8n webhook request time out?
Because the caller is holding the connection open while the workflow does its work, and it or an intermediate proxy gives up first. Put the Respond node early, return 202 Accepted immediately after validation, and let the remaining work run after the response has been sent.
What is the difference between the n8n test and production webhook URLs?
The test URL only listens while you have clicked Listen for test event in the editor, and accepts one request. The production URL works whenever the workflow is active. A test that works and a production URL returning 404 means the workflow was never activated.
How do I return an error status code from an n8n webhook?
Set the Response Code option on the Respond to Webhook node. Use 4xx for permanently invalid input and 5xx only for genuinely transient failures — many senders retry on 5xx and give up on 4xx, so getting this backwards causes either infinite retries or silently dropped data.