The Webhook node is the most powerful and versatile trigger in n8n. It transforms n8n into a real-time API endpoint that any external system can call β Stripe, GitHub, Typeform, your own application, or any service that can make HTTP requests.
In this complete tutorial, you'll learn everything about webhooks in n8n: what they are, how to create and configure them, the difference between test and production modes, authentication options, how to process incoming data with expressions, and how to send data to external services with the HTTP Request node.
How to create a Webhook trigger Β· Test vs production mode Β· Authenticating webhooks Β· Processing webhook data Β· Responding to webhooks Β· Stripe webhook integration Β· GitHub webhook integration Β· Sending HTTP requests from n8n Β· Common troubleshooting tips
What Are Webhooks? A Quick Primer
Webhooks are a mechanism for one application to notify another when something happens, using HTTP. Instead of your application continuously asking "did anything change?" (polling), the external service pushes data to you the moment an event occurs.
Think of webhooks as "reverse APIs":
- Traditional API call: Your app β asks β External service β responds
- Webhook: External service β pushes data β Your endpoint (n8n)
Common real-world examples:
- Stripe: Sends a webhook when a payment succeeds, subscription renews, or refund is issued
- GitHub: Sends a webhook on push, pull request, issue creation, or deployment
- Typeform / JotForm: Sends form response data when someone submits a form
- Shopify: Sends order data when a new purchase is completed
- Your own app: Can send webhooks to trigger n8n workflows from any user action
Creating Your First Webhook Trigger in n8n
Setting up a Webhook trigger in n8n takes under 2 minutes. Here's the step-by-step process:
Create a New Workflow
Open n8n, click New Workflow in the top right. The workflow canvas will open with an empty state.
Add the Webhook Node
Click the + button (or press Tab) to open the node menu. Search for "Webhook" and select the Webhook trigger node. It will appear as the first node in your workflow.
Configure the Webhook
Click the Webhook node to open its settings panel. Configure:
- HTTP Method: POST (for receiving data), GET (for simple triggers), or any other method
- Path: A unique URL path (e.g.,
my-workfloworstripe-events) - Authentication: None for now (we'll cover auth later)
- Respond: Immediately (returns 200 OK at once) or When Last Node Finishes
Copy Your Webhook URL
n8n generates two URLs after configuration. You'll see them in the node panel:
Test the Webhook
Click "Listen for Test Event" in the node. Then send a test request to the test URL. n8n will capture the incoming data and display it in the node output panel.
Test Mode vs Production Mode
Understanding the two webhook modes is critical β mixing them up is one of the most common n8n mistakes.
| Feature | Test URL (/webhook-test/) | Production URL (/webhook/) |
|---|---|---|
| When Active | Only when you click "Listen for Test Event" in the editor | Always active when workflow is enabled |
| Execution Saved | No β shows data in editor but doesn't save | Yes β full execution log in History |
| Timeout | 120 seconds (waits for request then auto-closes) | No timeout β always listening |
| Simultaneous Requests | One at a time only | Multiple concurrent requests supported |
| Use For | Development and testing only | Real production traffic |
The test URL only works when you have the workflow open in the editor and have clicked "Listen for Test Event." If you use the test URL as a webhook endpoint in Stripe, GitHub, or any external service, their webhooks will fail 99% of the time (when you're not actively testing). Always use the production URL for real integrations.
Webhook Authentication
Without authentication, anyone who discovers your webhook URL can send requests and trigger your workflow. n8n offers several authentication methods:
Option 1: Header Authentication
The most common approach. The external service sends a secret key in a specific HTTP header. n8n validates the header value before executing the workflow.
Option 2: Basic Authentication
Uses standard HTTP Basic Auth with username and password. The credentials are sent in the Authorization header as base64-encoded "username:password".
Option 3: Signature Verification (Stripe, GitHub Pattern)
Many services like Stripe and GitHub sign their webhook payloads with HMAC-SHA256. You verify the signature to confirm the request is genuine. This requires the Code node:
Processing Webhook Data with Expressions
When a webhook request arrives, n8n structures the incoming data with these top-level fields:
Access this data in subsequent nodes using n8n expressions:
Responding to Webhooks
Many services expect a specific response to their webhooks. n8n offers three response modes:
Mode 1: Respond Immediately
n8n returns HTTP 200 as soon as the webhook is received, without waiting for the workflow to finish. Use this for fire-and-forget scenarios where the sending service doesn't need a response.
Mode 2: When Last Node Finishes
n8n waits for the entire workflow to complete, then returns the output of the last node as the response body. Use this when the caller expects data back (e.g., a synchronous API call pattern).
Mode 3: Respond to Webhook Node
The most flexible mode. Place the Respond to Webhook node anywhere in your workflow to send a custom response at any point, then continue the workflow asynchronously.
Stripe marks webhooks as failed if they don't receive a 2xx response within 30 seconds. Use Respond Immediately or the Respond to Webhook node early in your workflow, then continue processing asynchronously. This prevents Stripe from retrying and flooding your workflow.
Real Example: Processing Stripe Webhooks
Let's build a complete Stripe payment webhook workflow that:
- Receives a Stripe
payment_intent.succeededevent - Immediately responds with 200 (to prevent Stripe retries)
- Extracts payment details
- Saves the record to Google Sheets
- Sends a confirmation email to the customer
- Notifies the team in Slack
Webhook Node (POST, path: stripe-events)
HTTP Method: POST | Authentication: None (we verify signature in code) | Respond: Using 'Respond to Webhook' Node
Code Node: Verify Stripe Signature
Validates the Stripe webhook signature using crypto (see code above). Throws an error for invalid signatures, which stops the workflow.
IF Node: Filter Event Types
Condition: {{ $json.type }} equals payment_intent.succeeded
True branch continues; False branch ends quietly.
Respond to Webhook Node
Immediately returns {"received": true} with HTTP 200. Stripe receives the confirmation. Workflow continues asynchronously.
Set Fields Node: Extract Payment Data
Parallel: Google Sheets + Gmail + Slack
Three nodes run in parallel from the Set Fields output:
- Google Sheets: Append row to "Payments" sheet
- Gmail: Send HTML receipt to {{ $json.email }}
- Slack: Post to #revenue channel: "π° New payment: ${{ $json.amount }} from {{ $json.name }}"
Real Example: GitHub Webhook for CI/CD Notifications
This workflow receives GitHub push events and sends team notifications:
Configure GitHub to send webhooks to your n8n URL:
- Go to your GitHub repository β Settings β Webhooks β Add webhook
- Set Payload URL to your n8n production webhook URL
- Content type:
application/json - Secret: generate a random secret and add it to n8n's Header Auth credential
- Select events: Push, Pull Request, or specific events
n8n Expressions for GitHub Data
Sending Data Out: HTTP Request Node
The flip side of receiving webhooks is sending them β calling external APIs and webhooks from your n8n workflow. The HTTP Request node handles all outgoing HTTP calls.
Basic POST Request
GET Request with Query Parameters
Handling API Pagination
Many APIs paginate their responses. The HTTP Request node has built-in pagination support:
Webhook Use Case: Form Submissions
Processing form submissions is one of the most common webhook use cases. Here's how to handle Typeform, HubSpot forms, and custom HTML forms:
Typeform Webhook
Configure in Typeform: Connect β Webhooks β add your n8n URL.
Custom HTML Form β n8n Webhook
You can post directly from any HTML form to an n8n webhook using JavaScript:
Common Webhook Issues & Solutions
Issue 1: Webhook Not Receiving Data
- Check: Are you using the production URL (not test URL) and is the workflow enabled?
- Check: Is n8n accessible from the internet? (Self-hosted instances behind a firewall won't receive external webhooks)
- Check: Is the webhook URL in the external service correct (including https://, correct domain)?
- Fix: Use a tool like ngrok during development to expose local n8n to the internet
Issue 2: 401 Unauthorized
- Cause: Authentication is configured on the webhook but the sender isn't providing correct credentials
- Fix: Temporarily disable authentication to test, then re-enable after confirming basic connectivity
Issue 3: Workflow Triggers But Data is Empty
- Cause: The sending service uses form encoding instead of JSON
- Fix: Check the Content-Type header. For
application/x-www-form-urlencoded, data is in$json.bodyas flat key-value pairs
Issue 4: Webhook Times Out
- Cause: Workflow takes longer than the service's timeout window (e.g., Stripe's 30 seconds)
- Fix: Use Respond to Webhook node at the beginning to send an immediate 200, then continue processing
Use a service like webhook.site or requestbin.com to inspect the exact payload a service sends before configuring n8n. Point the external service at the inspection URL temporarily, examine the data structure, then configure your n8n workflow accordingly.
Webhook Security Best Practices
- Always use HTTPS: Never expose n8n over plain HTTP in production. Use a reverse proxy (Nginx/Caddy) with SSL certificates from Let's Encrypt.
- Validate signatures when available: Services like Stripe, GitHub, and Shopify sign their webhooks. Always verify the signature before processing the payload.
- Use secret paths: Instead of
/webhook/orders, use a UUID-like path:/webhook/orders-a7f8b2c9d0e1. This adds obscurity on top of authentication. - Rate limit your webhooks: Add IP-based rate limiting at the Nginx level to prevent flooding.
- Respond quickly, process async: Use the Respond to Webhook node to return 200 immediately, then continue processing to prevent timeouts.
- Log webhook requests: Store incoming webhook data in a database or Google Sheet for audit trail and replay capabilities.