Core nodes12 min readUpdated 2026-06-29

n8n Webhooks: The Complete Tutorial

Receive, validate, and respond to webhooks in n8n. Covers HMAC verification, idempotency, queue mode, and debugging.

Key takeaways

  • Use the Production URL, not the Test URL, once you go live.
  • Always verify the signature on webhooks from Stripe, GitHub, Shopify, and any platform that signs payloads.
  • Respond with 200 within 5 seconds — push slow work into a sub-workflow.
  • Make handlers idempotent: the sender will retry.

The Webhook node is the most powerful trigger in n8n. It turns any URL into a workflow entry point and lets you build APIs, ingest third-party events, and run AI tools that respond in real time. This tutorial covers everything from a first hello-world to production-grade signature verification.

Your first webhook

Drop a Webhook node, set the HTTP method to POST, and copy the Test URL. Click Listen for Test Event, then curl the URL with a JSON body. The payload appears in the node — you can now reference $json.body.anything downstream.

Test URL vs Production URL

The Test URL only listens while the editor is open and a Listen click is active. The Production URL is live whenever the workflow is Active. Switch all external systems to the Production URL before going live, or you will silently drop events.

Verify signatures the right way

Every serious webhook sender signs payloads with HMAC-SHA256 over the raw body using a shared secret. Use a Code node to recompute the signature and compare with crypto.timingSafeEqual. Reject mismatches with a 401. Do not skip this in production — unsigned webhooks become attack surface.

Respond fast, work slow

Set Respond to Immediately or use the Respond to Webhook node early. Push slow work (LLM calls, third-party APIs) into a sub-workflow called via the Execute Workflow node with the wait-for-completion flag off. Senders typically time out at 5–10 seconds.

Idempotency

Senders retry on any non-2xx, on network blips, and sometimes on success they did not see. Dedupe on the event ID provided by the sender (Stripe event.id, GitHub X-GitHub-Delivery, Shopify X-Shopify-Webhook-Id). A small Postgres seen_events table is the standard pattern.

Frequently asked questions

Why does my webhook return 404 in production?
You're hitting the Test URL or the workflow isn't Active. Toggle the workflow Active and use the Production URL.
How big a payload can the webhook accept?
Default 16 MB. Configure N8N_PAYLOAD_SIZE_MAX to raise it.
Can n8n stream webhook responses?
Yes via the Respond to Webhook node with streaming for SSE and chunked responses.
HomePathTemplatesBlogMy