How to Use n8n Webhooks: Complete Tutorial with Real Examples
Most n8n workflows start with a Schedule Trigger — they run on a timer. Webhooks flip this around: instead of n8n checking for data, external apps push data to n8n the moment something happens. A new Stripe payment, a GitHub push, a form submission — all of these can fire your workflow instantly, with zero polling overhead.
What Is a Webhook in n8n?
A webhook is an HTTP endpoint that n8n exposes for you. When an external service sends a POST (or GET) request to that URL, n8n receives the request, makes the payload available as workflow data, and runs everything downstream.
n8n generates two URLs per webhook node:
- Test URL: Only active when you click "Listen for Test Event" in the editor. Use this while building.
- Production URL: Always active when the workflow is activated. Use this in your source apps.
The URLs look like: https://your-n8n.n8nautomation.cloud/webhook/your-path
Step 1: Add and Configure the Webhook Node
Open a new workflow and add a Webhook node as the trigger. Configure these settings:
- HTTP Method: POST for most services. GET for simple URL-based triggers.
- Path: A custom path segment for the URL. Use something descriptive like
stripe-paymentorgithub-push. Avoid generic names likewebhook1. - Authentication: None to start — add this after you confirm the basics work. See the Securing section below.
- Respond: "Immediately" returns a 200 to the sender before your workflow finishes. Use this for services that expect a fast acknowledgment (Stripe, GitHub). "When Last Node Finishes" holds the response open — use this if you need to return computed data.
Path uniqueness: Each path must be unique within your n8n instance. If you have multiple webhook workflows, give each a distinct path. Reusing the same path on two active workflows will cause conflicts.
Step 2: Test with a Real Request
Click "Listen for Test Event" in the Webhook node. n8n is now waiting. Send a test request to the Test URL:
curl -X POST https://your-n8n.n8nautomation.cloud/webhook-test/stripe-payment \
-H "Content-Type: application/json" \
-d '{"type": "payment_intent.succeeded", "amount": 2000}'
n8n will receive the request, display the payload in the data panel, and let you inspect the structure. Build the rest of your workflow using the actual field names from this test payload — {{ $json.type }}, {{ $json.amount }}, etc.
Once the workflow is working, activate it (top-right toggle). Now switch your source app to use the Production URL instead of the Test URL.
Real-World Examples
Stripe Payment Notifications
In your Stripe Dashboard → Developers → Webhooks, add the production URL with event type payment_intent.succeeded. Your n8n workflow receives the full Stripe event object — charge amount, customer ID, metadata — and can log it to a spreadsheet, send a Slack notification, or trigger order fulfilment.
GitHub Push Triggers
In your GitHub repo → Settings → Webhooks, add the URL with content type application/json and select "Just the push event". Your workflow fires on every git push — automatically run tests, post a deploy notification to Slack, or update a project tracker.
Typeform / Tally Form Submissions
In Typeform → Connect → Webhooks, paste your n8n URL. Every form submission lands in your workflow with all field responses. Route to different paths based on answers, send confirmation emails, or create CRM records — all without a Zapier middleman.
Securing Your Webhook
An unsecured webhook URL can be called by anyone. For production workflows, add one of these protections:
- Header Auth: Require a custom header with a secret value. Simple and works with most services.
- Basic Auth: Username and password in the URL. Supported by most webhook senders.
- Signature Verification: Services like Stripe and GitHub sign their webhook payloads with an HMAC signature. In a Code node, verify the signature before processing. Stripe provides the
stripe-signatureheader; GitHub usesx-hub-signature-256.
// Verify Stripe webhook signature in a Code node
const crypto = require('crypto');
const secret = 'whsec_your_stripe_webhook_secret';
const payload = $input.first().json.rawBody;
const sig = $input.first().json.headers['stripe-signature'];
const computed = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (!sig.includes(computed)) throw new Error('Invalid signature');
return $input.all();
Common Issues and Fixes
- Workflow not triggering: Check that the workflow is activated (not just saved). Test URL only works with "Listen for Test Event" active.
- 504 Gateway Timeout: Your workflow is taking too long and the sender timed out. Set Respond to "Immediately" so n8n acknowledges the request before processing.
- Webhook URL not accessible: Your n8n instance needs to be publicly reachable. Self-hosted n8n behind a local network won't receive external webhooks — use a managed instance or set up a tunnel.
- Payload not showing expected fields: Check the Content-Type header. n8n parses JSON automatically but form data requires
application/x-www-form-urlencodedcontent type handling.