How to Build Real-Time Webhook Workflows with n8n (Trigger, Route, and Respond to Any Event)
Build n8n webhook workflows that capture any real-time event, validate it, route it to the right action, and respond in seconds — no polling required.
Polling Is Dead. Webhooks Are How Events Actually Happen.
Schedule triggers are useful for batch jobs. But for anything time-sensitive — a payment completed, a form submitted, a GitHub push, a support ticket opened — checking every few minutes is the wrong architecture.
Webhooks let the event source push data to your workflow the instant something happens. No polling lag, no wasted API calls, no missed events between check intervals.
n8n's Webhook node turns any HTTP POST into a workflow trigger. One endpoint handles Stripe payment events. Another routes GitHub CI failures. Another processes Typeform submissions — all in real time, all automated.
What You Can Automate With Webhooks
Webhooks work wherever an external system can fire an HTTP request:
- Payment events — Stripe
payment_intent.succeeded,charge.failed,customer.subscription.deleted - Form submissions — Typeform, Tally, Webflow, or any form tool that POSTs on submit
- Git events — GitHub or GitLab push, pull request opened, CI run failed
- Support tickets — new ticket in Zendesk, Intercom, or Freshdesk
- E-commerce events — Shopify order created, inventory low, refund requested
- Auth events — new user signed up via Auth0, Clerk, or Supabase
- Inbound messages — Slack slash commands, Telegram bot messages, SMS from Twilio
- Custom product events — any event your app backend fires via a single HTTP call
The Webhook Pipeline
A production-grade n8n webhook workflow follows this shape:
Webhook Trigger (POST /webhook/<id>)
→ Code (validate signature, parse + normalize payload)
→ Switch (route by event_type)
→ payment_succeeded: Sheets (log) → Gmail (receipt) → Slack (alert)
→ payment_failed: Gmail (dunning email) → Slack (urgent alert)
→ subscription_deleted: Gmail (offboarding) → CRM (update status)
→ unknown_event: HTTP Request (log to dead-letter endpoint)
→ Respond to Webhook (200 OK)
Every event arrives at a single endpoint, gets validated and parsed, gets routed to the right action, and gets acknowledged — all within a few hundred milliseconds.
1. Collect — Expose the Webhook Endpoint
The Webhook node gives you an instant HTTPS endpoint. Set the HTTP method to POST and copy the production URL from the node settings panel.
Paste that URL into Stripe's webhook dashboard, Typeform's notification settings, GitHub's repository hooks, or anywhere that accepts a webhook target.
The node passes the full request to the next node: body, headers, query params, and raw body (important for signature verification).
2. Process — Validate and Normalize
Before routing, a Code node does two things.
Signature check — most services sign the payload so you can verify it's genuine:
const crypto = require("crypto");
const secret = "YOUR_WEBHOOK_SECRET";
const signature = $input.first().headers["stripe-signature"];
const rawBody = JSON.stringify($input.first().body);
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
if (!signature.includes(expected)) {
throw new Error("Invalid webhook signature — request rejected");
}
return $input.all();
Normalization — extract the fields every downstream node needs:
const body = $json.body;
return [{
json: {
event_type: body.type,
event_id: body.id,
customer_email: body.data?.object?.customer_email ?? "",
amount_cents: body.data?.object?.amount ?? 0,
currency: body.data?.object?.currency ?? "usd",
created_at: new Date(body.created * 1000).toISOString()
}
}];
An open webhook endpoint with no signature check will process any POST request anyone sends it. Validate the HMAC before running any business logic. A single throw in the Code node stops the workflow and returns a non-200 to the caller — which is exactly what you want on a forged request.
3. Route — Branch by Event Type
A Switch node reads event_type from the normalized payload and routes to the correct branch.
Keep routing logic in the Switch node — not in nested IFs inside a Code node. One condition per branch, one branch per event type. Unknown event types go to a dead-letter branch that logs the raw payload for debugging.
Switch (event_type)
→ "payment_intent.succeeded" → payment success branch
→ "payment_intent.payment_failed" → payment failure branch
→ "customer.subscription.deleted" → cancellation branch
→ default → HTTP Request (POST /logs/unhandled-events)
4. Act — Execute the Right Response
Each branch runs its own action sequence. A payment success branch might:
- Google Sheets — append a row to the revenue log
- Gmail — send the customer a payment receipt
- Slack — post a payment alert to
#payments - HTTP Request — call your CRM API to tag the contact as
paying
A payment failure branch does different things:
- Gmail — send a dunning email with a payment retry link
- Slack — post an urgent alert to
#billing-alerts - Google Sheets — log the failure with retry count for follow-up tracking
Webhook workflows need to complete fast. If a branch needs to process many records, write the job to a queue — a Sheets row or a database entry — and let a separate Schedule Trigger pick it up. The webhook workflow's job is to receive, validate, and hand off, not to do heavy processing inline.
5. Follow Up — Acknowledge the Sender
The final node in every branch is a Respond to Webhook node.
Stripe requires a 200 OK within 30 seconds or it retries the event. Slack slash commands require a response within 3 seconds or they show a timeout error.
{
"received": true,
"event": "payment_intent.succeeded"
}
Set the HTTP status code to 200. If your workflow errored, n8n returns a non-200 automatically — the sender retries, and the failure appears in your execution log.
During development, expose your local n8n instance with ngrok. Run ngrok http 5678, copy the HTTPS URL, and paste it as the webhook target in your service's test mode. Trigger test events and inspect the raw payload before building the routing logic. This is faster than deploying to a cloud instance for every iteration.
Implementation Patterns
Pattern 1 — Multi-Event Single Endpoint
One endpoint handles all event types from a single service:
Webhook (POST /stripe-events)
→ Code (verify signature, extract event_type)
→ Switch (event_type)
→ payment_succeeded: log + receipt email + Slack alert
→ payment_failed: dunning email + urgent Slack alert
→ subscription_created: welcome sequence trigger
→ subscription_deleted: offboarding sequence trigger
→ invoice_upcoming: payment reminder email
→ default: log to unhandled-events sheet
One URL in Stripe's dashboard. All events flow through one validation step. Adding a new event type means adding one Switch branch — nothing else changes.
Pattern 2 — Cross-Service Fan-Out
One incoming event triggers actions across multiple services simultaneously:
Webhook (POST /new-signup — from your product backend)
→ Code (parse: email, plan, source)
→ [parallel branches]
→ Branch A: HTTP Request (create HubSpot contact)
→ Branch B: Gmail (send welcome email)
→ Branch C: Slack (alert #sales with plan and source)
→ Branch D: Google Sheets (log to onboarding tracker)
→ Respond to Webhook (200 OK)
n8n runs the parallel branches concurrently. All four actions complete before the final response node fires.
Pattern 3 — Webhook-to-Queue for Heavy Processing
When the event triggers work that takes more than a few seconds:
Webhook (POST /export-requested)
→ Code (extract: user_id, export_type, filters)
→ Google Sheets (append row: status=pending, requested_at=now)
→ Respond to Webhook (202 Accepted)
[Separate workflow — Schedule Trigger every 2 minutes]
→ Sheets (rows where status=pending)
→ HTTP Request (call export API — may take 5-30s per row)
→ Code (build download link from response)
→ Gmail (send download link to user)
→ Sheets (update row: status=complete)
The webhook responds immediately with 202 Accepted. The heavy work runs in a background workflow that never blocks the HTTP response.
The Data Entry Hub template uses a similar queue pattern — webhooks write to a central sheet, a separate workflow processes each row on a schedule.
n8n Nodes You'll Use Most
| Node | Purpose |
|---|---|
| Webhook | Expose an HTTPS endpoint; receive body, headers, and query params |
| Respond to Webhook | Send a custom HTTP status and body back to the caller |
| Code | Validate signatures, normalize payloads, build response bodies |
| Switch | Route by event_type or any field in the normalized payload |
| IF | Binary conditions — signature valid/invalid, amount above threshold |
| HTTP Request | Call external APIs in response to the event |
| Gmail | Send event-driven emails: receipts, alerts, dunning |
| Google Sheets | Log events, queue jobs, track processing status |
| Slack | Post real-time alerts to team channels |
| Wait | Pause mid-workflow before sending a follow-up message |
Getting Started
- Pick one event source and one event type — start with Stripe
payment_intent.succeededor a Typeform submission. One service, one event. - Create the Webhook node — set method to
POST, copy the production URL. - Register the URL — paste it into the service's webhook settings. Enable test mode if available.
- Fire a test event — use the service's "send test" button. Watch the n8n execution log to see the raw payload structure.
- Add the Code node — implement signature verification and normalization using the real field paths from the test payload.
- Add the Switch node — one branch for the event type you're handling. Add a default branch that logs unknowns to a Google Sheet.
- Build the action branch — wire up Sheets, Gmail, Slack, or your CRM. Add a Respond to Webhook node at the end of every branch.
Once the first event type is working end to end, adding branches for additional event types is fast — the validation and routing infrastructure already exists.
For workflows that send emails or Slack messages as part of their response, see n8n email inbox automation and n8n Slack automation. For handling the data that webhook events write to spreadsheets, see the guide to n8n data reporting automation.
If you're building a subscription billing pipeline on top of Stripe webhooks, the Smart Subscription Manager and Email Follow-up Automator templates give you a working starting point with the routing logic already wired up.
Browse real-time event automation templates for n8n →Common questions
What's the difference between a webhook trigger and a schedule trigger in n8n?
How do I validate that a webhook request is genuine in n8n?
Can n8n respond back to the webhook sender within the same request?
Get the workflow templates this guide is built on
Import-ready n8n JSON, step-by-step setup, and tested end-to-end. One-time payment, own it forever.
More automation guides

How to Automate Customer Onboarding with n8n (Welcome Sequences, Tasks, and Activation)
Manual Onboarding Is the Leakiest Part of Your Funnel Most SaaS products lose 40–60% of new sign-ups before they reach the first value moment. Not because the product is bad — because the handoff from…
How to Automate Expense Tracking, Budget Alerts, and Spend Reports with n8n
Your Expense Reports Are Still Manual. They Shouldn't Be. Every finance team has the same problem: receipts pile up in email, budget alerts arrive a week after the damage is done, and month-end report…

How to Automate Airtable with n8n (Sync, Update, and Trigger Workflows from Your Database)
Airtable Is Your Database. n8n Makes It Behave Like a Full Automation Platform. Airtable is where teams store structured data — project trackers, CRM records, content calendars, inventory, hiring pipe…