n8n Webhook Node
🔗
Trigger Node

n8n Webhook Node

Master the n8n Webhook node to receive external data and trigger workflows. Learn test vs production URLs, authentication, response handling, path parameters, and security best practices.

Webhooks are the backbone of real-time automation. When a customer places an order, when a payment succeeds, when someone submits a form, when code gets pushed to a repository, these events happen outside n8n. The Webhook node is how you bring those events into your workflows and respond instantly.

Unlike scheduled triggers that poll for data periodically, webhooks push data to your workflow the moment something happens. This makes them essential for time-sensitive automations where delays matter: payment processing, lead capture, alerting systems, and real-time integrations.

The Webhook Configuration Challenge

Setting up webhooks in n8n seems straightforward until it stops working. The workflow looks correct. The external service says it sent the data. But nothing happens. No execution. No error. Just silence.

The problem is usually one of three things: the wrong URL, incorrect authentication, or a misunderstanding of how n8n’s test and production modes work. This guide covers all of these in depth so you can debug webhook issues in minutes, not hours.

What You’ll Learn

  • The critical difference between test and production webhook URLs (the #1 source of confusion)
  • How to configure authentication to secure your webhooks
  • Response handling options for different use cases
  • Dynamic path parameters for flexible endpoint routing
  • Troubleshooting the most common webhook problems
  • Security best practices for production deployments
  • Real-world examples you can adapt to your workflows

When to Use the Webhook Node

The Webhook node is a trigger node. It starts your workflow when an external service sends an HTTP request to your n8n instance. Before diving into configuration, understand when webhooks are the right choice versus other trigger options.

ScenarioBest TriggerWhy
Stripe payment notificationWebhookStripe sends events immediately when payments occur
GitHub push/PR eventsWebhookGitHub webhooks provide real-time repository updates
Form submission from websiteWebhookYour form can POST directly to the n8n endpoint
Process data every hourSchedule TriggerNo external event, just time-based execution
New email arrivesEmail Trigger or IMAPDedicated email triggers handle authentication
Manual workflow runManual TriggerUser clicks execute in n8n interface
New row in Google SheetsGoogle Sheets TriggerNative trigger polls for changes
Custom internal serviceWebhookYour service can call the webhook URL

Rule of thumb: If an external service can send HTTP requests to a URL when events happen, use a Webhook. If you need to check for changes periodically, use a native app trigger or Schedule Trigger.

Webhook vs HTTP Request Node

New users sometimes confuse these nodes:

  • Webhook node: Receives incoming HTTP requests (listens for data from external services)
  • HTTP Request node: Sends outgoing HTTP requests (fetches data from external APIs)

Think of it this way: Webhook is the doorbell that starts your workflow. HTTP Request is you going out to get something.

Understanding Webhook URLs

Every Webhook node generates two URLs: a test URL and a production URL. Understanding the difference between these is critical because using the wrong one is the most common webhook mistake.

Test URL vs Production URL

AspectTest URLProduction URL
URL path/webhook-test/.../webhook/...
When activeOnly while listening in editorOnly when workflow is activated
Timeout120 secondsNo explicit timeout (server dependent)
Data displayShows in editor for debuggingVisible only in execution log
Use caseDevelopment and testingProduction integrations

Test URL behavior:

  1. Open your workflow in the n8n editor
  2. Click “Listen for Test Event” on the Webhook node
  3. n8n registers a temporary webhook that stays active for 120 seconds
  4. Send a request to the test URL
  5. Data appears in the node output panel for inspection
  6. If no request arrives within 120 seconds, the listener times out

Production URL behavior:

  1. Configure and save your workflow
  2. Toggle the workflow to “Active” (switch in top right)
  3. n8n registers a persistent webhook
  4. External services can send requests anytime
  5. Each request triggers a workflow execution
  6. View executions in the Executions tab

Common URL Mistakes

Mistake 1: Using test URL in production

Wrong: https://your-n8n.com/webhook-test/abc123
Right: https://your-n8n.com/webhook/abc123

The test URL only works when you have the editor open and are actively listening. If you configure Stripe to use a test URL, webhooks fail when you close the browser.

Mistake 2: Workflow not activated

You copied the production URL correctly, but the workflow toggle is off. Production webhooks only work when the workflow is active. Check the toggle in the top right of the editor.

Mistake 3: URL path typo

Webhook paths are case-sensitive. If your path is myWebhook and you call mywebhook, it fails. Double-check the exact URL shown in the node.

Webhook URL Structure

The full webhook URL consists of:

https://[your-n8n-domain]/webhook/[path]

For self-hosted instances, configure the base URL with the WEBHOOK_URL environment variable. For n8n Cloud, the domain is your instance URL.

The path is either auto-generated (a random string) or custom-defined. Custom paths make URLs more readable and meaningful:

Auto-generated: /webhook/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Custom path:    /webhook/stripe-payments
Custom path:    /webhook/github-push

Your First Webhook

Let’s create a working webhook from scratch and test it with a real request.

Step 1: Add the Webhook Node

  1. Open n8n and create a new workflow
  2. Click + to add a node
  3. Search for “Webhook”
  4. Click to add it as your trigger

The node appears with configuration options on the right panel.

Step 2: Configure Basic Settings

With the Webhook node selected:

  1. HTTP Method: Leave as POST (most common for webhooks)
  2. Path: Enter a custom path like my-first-webhook or leave the auto-generated one
  3. Authentication: Leave as “None” for testing
  4. Respond: Leave as “Immediately”

You’ll see both the test and production URLs at the top of the panel.

Step 3: Test with curl

Copy the test URL, then click “Listen for Test Event” to start listening.

Open a terminal and send a test request:

curl -X POST https://your-n8n.com/webhook-test/my-first-webhook \
  -H "Content-Type: application/json" \
  -d '{"name": "Test User", "email": "[email protected]", "amount": 99.99}'

Step 4: Verify the Data

After sending the request, the Webhook node shows the received data:

{
  "headers": {
    "content-type": "application/json",
    "user-agent": "curl/7.88.1"
  },
  "params": {},
  "query": {},
  "body": {
    "name": "Test User",
    "email": "[email protected]",
    "amount": 99.99
  }
}

You can now access this data in subsequent nodes:

  • {{ $json.body.name }} returns “Test User”
  • {{ $json.body.email }} returns “[email protected]
  • {{ $json.body.amount }} returns 99.99

For more on working with data in expressions, see our n8n expressions guide.

Step 5: Activate for Production

Once testing is complete:

  1. Connect additional nodes to process the data
  2. Save the workflow
  3. Toggle the workflow to “Active”
  4. Use the production URL (without -test) in your external service

HTTP Methods

The Webhook node supports standard HTTP methods. Each method has conventional uses, though your external service dictates which one to use.

MethodConventional UseCommon Webhook Scenarios
POSTSend data to be processedPayment events, form submissions, most webhooks
GETRetrieve informationHealth checks, verification callbacks
PUTReplace a resource entirelyFull record updates
PATCHPartial updateIncremental changes
DELETERemove a resourceDeletion notifications
HEADHeaders only (no body)Connectivity checks

POST is the default and most common. Nearly all webhook providers (Stripe, GitHub, Shopify, HubSpot) use POST to send event data.

Accepting Multiple HTTP Methods

By default, the Webhook node accepts only the method you select. If a service sends POST but your webhook expects GET, the request fails silently.

To accept multiple methods:

  1. Open the Webhook node
  2. Click the gear icon for Settings
  3. Enable Allow Multiple HTTP Methods
  4. Select all methods you want to accept

This is useful for services that send different event types with different methods, or when building REST-like endpoints.

Authentication Methods

Public webhooks are security risks. Anyone who discovers your URL can trigger your workflow with fake data. For production deployments, always configure authentication.

The Webhook node supports four authentication methods. Choose based on what your external service supports and your security requirements.

No Authentication

Use only for testing or internal services on private networks.

No configuration needed. Any request to the URL triggers the workflow.

Header Authentication

The most common method for custom integrations. You define a secret header that callers must include.

Configuration:

  1. Set Authentication to “Header Auth”
  2. Create credentials with:
    • Header Name: e.g., X-Webhook-Secret
    • Header Value: A long random string

Caller must include:

curl -X POST https://your-n8n.com/webhook/my-endpoint \
  -H "X-Webhook-Secret: your-secret-value-here" \
  -H "Content-Type: application/json" \
  -d '{"event": "test"}'

Requests without the correct header receive a 401 Unauthorized response.

Basic Authentication

Standard HTTP basic auth using username and password.

Configuration:

  1. Set Authentication to “Basic Auth”
  2. Create credentials with username and password

Caller authenticates with:

curl -X POST https://your-n8n.com/webhook/my-endpoint \
  -u "username:password" \
  -H "Content-Type: application/json" \
  -d '{"event": "test"}'

Basic auth credentials are Base64-encoded (not encrypted), so always use HTTPS.

JWT Authentication

For services that send JSON Web Tokens.

Configuration:

  1. Set Authentication to “JWT Auth”
  2. Configure the JWT secret or public key for verification

The Webhook node validates the token signature and optionally checks claims like expiration.

Authentication Comparison

MethodSecurity LevelComplexityBest For
NoneLowTrivialTesting only
Header AuthMediumEasyCustom integrations, internal services
Basic AuthMediumEasyLegacy systems
JWT AuthHighComplexOAuth flows, user-context webhooks

For payment webhooks and high-value integrations, authentication alone is not enough. You should also verify webhook signatures. See our comprehensive webhook security guide for HMAC verification patterns.

If you run into authentication issues, check our guide to fixing n8n authentication errors.

Response Handling

When a service sends a webhook, it usually expects a response confirming receipt. The Webhook node offers four response modes that control what and when you send back.

Immediately

Returns a response as soon as the webhook is received, before the workflow processes the data.

Response:

HTTP/1.1 200 OK
{"message": "Workflow was started"}

Use when:

  • The caller does not need processed data back
  • Your workflow takes a long time to complete
  • You want to acknowledge receipt quickly (important for timeout-sensitive services)

This is the default and most common mode.

When Last Node Finishes

Waits for the entire workflow to complete, then returns the output of the last executed node.

Response:

HTTP/1.1 200 OK
{"result": "processed", "orderId": "12345", "status": "confirmed"}

Use when:

  • Building API-like endpoints that return processed data
  • The caller needs the result of your workflow
  • Workflow execution is fast enough to avoid timeouts

Caution: Long-running workflows may timeout. n8n Cloud uses Cloudflare, which enforces a 100-second timeout. Self-hosted instances depend on your reverse proxy configuration. For timeout troubleshooting, see our timeout errors guide.

Using Respond to Webhook Node

Provides full control over the response using a separate Respond to Webhook node.

Configuration:

  1. Set Webhook response to “Using ‘Respond to Webhook’ Node”
  2. Add a Respond to Webhook node anywhere in your workflow
  3. Configure the response body, status code, and headers

Example: Custom error response

// In Respond to Webhook node
{
  "success": false,
  "error": "Invalid order ID",
  "code": "INVALID_ORDER"
}

With status code 400 Bad Request.

Use when:

  • You need conditional responses (success vs error)
  • Different branches should return different data
  • You need custom HTTP status codes or headers

Streaming Response

Returns data progressively as the workflow executes. Useful for AI/LLM workflows where you want to stream tokens back to the caller.

Requirements:

  • Workflow must contain nodes that support streaming (AI agent nodes)
  • Caller must handle streaming responses

Use when:

  • Building chat interfaces with LLMs
  • Long operations where users benefit from progressive feedback

Path Parameters

Path parameters let you create dynamic webhook endpoints that capture data from the URL itself. Instead of a single static endpoint, you can route different resources through the same webhook.

Supported Path Formats

FormatExampleCaptured Parameters
Single variable/:idid
Path with variable/users/:userIduserId
Variable with path/:tenantId/eventstenantId
Multiple variables/:org/:repoorg, repo
Complex path/api/:version/:resource/:idversion, resource, id

Configuration

In the Webhook node Path field, include variables prefixed with ::

Path: /orders/:orderId
Full URL: https://your-n8n.com/webhook/orders/12345

When a request hits /webhook/orders/12345, the Webhook node captures:

{
  "params": {
    "orderId": "12345"
  },
  "body": { ... }
}

Access the parameter in subsequent nodes:

{{ $json.params.orderId }}  // Returns "12345"

Multi-Tenant Example

A common use case is routing webhooks for different customers or tenants:

Path: /:customerId/events

Different customers can use their own endpoints:

  • /webhook/acme-corp/events
  • /webhook/beta-inc/events
  • /webhook/gamma-llc/events

Your workflow can then route or process differently based on the customer ID.

When to Use Path Parameters

  • Resource identification: Capture IDs directly in the URL
  • API versioning: Include version in path like /v1/:resource
  • Multi-tenant systems: Route different organizations through the same workflow
  • RESTful patterns: Build REST-like endpoints with consistent URL structure

For simpler cases, query parameters (?id=123) work just as well and may be easier to configure in external services.

Handling Webhook Payloads

Once data arrives at your webhook, you need to access and process it. The Webhook node provides structured access to all parts of the incoming request.

Accessing Request Data

Data LocationExpressionExample
Request body{{ $json.body }}Posted JSON data
Specific body field{{ $json.body.fieldName }}Single value from body
Headers{{ $json.headers }}All request headers
Specific header{{ $json.headers['x-custom-header'] }}Single header value
Query parameters{{ $json.query }}URL query string params
Path parameters{{ $json.params }}Captured from URL path

JSON Body Example

If Stripe sends:

{
  "type": "payment_intent.succeeded",
  "data": {
    "object": {
      "id": "pi_12345",
      "amount": 2000,
      "currency": "usd"
    }
  }
}

Access the data with:

{{ $json.body.type }}                    // "payment_intent.succeeded"
{{ $json.body.data.object.id }}          // "pi_12345"
{{ $json.body.data.object.amount / 100 }} // 20.00 (Stripe amounts are in cents)

For complex expressions, test them first with our expression validator tool.

Headers Example

Headers are lowercase in n8n. Access them with bracket notation:

{{ $json.headers['content-type'] }}      // "application/json"
{{ $json.headers['x-webhook-signature'] }} // Signature for verification
{{ $json.headers['user-agent'] }}        // Caller identification

Query Parameters

If the URL is called with ?status=active&limit=10:

{{ $json.query.status }}  // "active"
{{ $json.query.limit }}   // "10" (string, convert if needed)

Binary Data and Files

For file uploads, the Webhook node can receive binary data. Enable binary handling in the node options, and the file becomes available as binary data for use with file processing nodes.

Payload Size Limits

The maximum webhook payload is 16MB by default. For self-hosted instances, adjust with the N8N_PAYLOAD_SIZE_MAX environment variable:

N8N_PAYLOAD_SIZE_MAX=32 # MB

For very large payloads, consider having the sender upload to cloud storage and send only a reference URL.

Common Issues and Troubleshooting

These are the problems that trip up most users, based on patterns from the n8n community forum.

Issue 1: Webhook Not Triggering

Symptoms: External service says it sent the webhook, but no execution appears in n8n.

Diagnosis checklist:

  1. Check URL type: Are you using the test URL with the workflow inactive? Switch to production URL and activate the workflow.

  2. Check workflow activation: The toggle in the top right must be on for production webhooks.

  3. Check URL path: Paths are case-sensitive. Verify the exact URL.

  4. Check HTTP method: If your webhook expects POST but the service sends GET, requests fail silently. Enable multiple methods in settings if needed.

  5. Check authentication: If authentication is configured, the caller must include valid credentials.

  6. Check network/firewall: For self-hosted, ensure your n8n instance is reachable from the internet on the webhook port.

Issue 2: Duplicate Webhook Events

Symptoms: The same event triggers multiple workflow executions.

Common causes:

  • Service retry behavior: Many services retry failed webhooks. If your workflow times out or returns an error, the service sends again.
  • Multiple workflow activations: Accidentally activating multiple versions of the same workflow.
  • Meta/Instagram specific: Facebook platforms are known to send duplicate deliveries; use idempotency keys to deduplicate.

Solutions:

  • Return a 200 response quickly using “Immediately” mode
  • Implement idempotency checking using an event ID
  • For Meta webhooks specifically, check if you’re processing the same message ID twice

Issue 3: Timeout Errors

Symptoms: Webhook returns error or the caller times out.

Causes:

  • Workflow takes too long to execute
  • n8n Cloud Cloudflare limit: 100 seconds
  • Self-hosted reverse proxy timeout

Solutions:

  • Use “Immediately” response mode for long workflows
  • Process asynchronously and send results via separate HTTP request
  • Increase timeout in reverse proxy configuration (self-hosted)

See our timeout troubleshooting guide for detailed solutions.

Issue 4: Authentication Failures

Symptoms: 401 Unauthorized errors when calling webhook.

Diagnosis:

  • Verify credentials match exactly (case-sensitive)
  • Check header name spelling
  • For basic auth, ensure username:password encoding is correct
  • Test with curl to isolate whether the issue is n8n or the calling service

Issue 5: Missing Body or Headers

Symptoms: $json.body is empty or undefined.

Causes:

  • Content-Type header mismatch (service sending form data, not JSON)
  • Body not included in request
  • n8n parsing issue

Solutions:

  • Check the exact Content-Type the caller is sending
  • For form data, access $json.body differently or parse manually
  • Log raw request data for debugging

Use our workflow debugger tool to diagnose these issues faster.

Security Best Practices

Webhooks are publicly accessible endpoints. Without proper security, attackers can trigger your workflows with malicious data.

Always Use Authentication in Production

Never deploy production webhooks without authentication. Header auth is the minimum:

# Secure request with header
curl -X POST https://your-n8n.com/webhook/orders \
  -H "X-Webhook-Secret: your-long-random-secret" \
  -H "Content-Type: application/json" \
  -d '{"orderId": 123}'

Generate secrets using cryptographically secure random generators, not simple passwords.

Verify Webhook Signatures

Major platforms (Stripe, GitHub, Shopify) sign webhooks using HMAC. This proves the request came from them and was not tampered with.

n8n does not have built-in HMAC verification, but you can implement it with a Code node:

const crypto = require('crypto');

const payload = JSON.stringify($json.body);
const signature = $json.headers['x-hub-signature-256']; // GitHub example
const secret = $env.GITHUB_WEBHOOK_SECRET;

const expected = 'sha256=' + crypto
  .createHmac('sha256', secret)
  .update(payload)
  .digest('hex');

if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
  throw new Error('Invalid signature');
}

return $json;

For complete HMAC verification patterns including Stripe and Shopify, see our webhook security guide.

Validate Input Data

Never trust webhook data blindly:

  • Check required fields exist before processing
  • Validate data types (is amount actually a number?)
  • Sanitize strings that will be used in database queries or displayed

Use HTTPS

Always use HTTPS for webhook endpoints. HTTP transmits credentials and data in plain text.

For self-hosted n8n, configure SSL termination at your reverse proxy (nginx, Caddy, Traefik).

Rate Limiting

Implement rate limiting at the reverse proxy level to prevent abuse:

limit_req_zone $binary_remote_addr zone=webhook_limit:10m rate=10r/s;

location /webhook/ {
    limit_req zone=webhook_limit burst=20 nodelay;
    proxy_pass http://localhost:5678;
}

This limits each IP to 10 requests per second with a burst allowance of 20.

For comprehensive security implementation, see our webhook security guide or explore our consulting services for professional security audits.

Real-World Examples

Example 1: Stripe Payment Webhook

Scenario: Process successful payments from Stripe.

Method: POST
Path: /stripe-payments
Authentication: None (use signature verification instead)
Response: Immediately

Stripe webhook payload structure:

{
  "type": "payment_intent.succeeded",
  "data": {
    "object": {
      "id": "pi_12345",
      "amount": 5000,
      "customer": "cus_abc123"
    }
  }
}

Workflow pattern:

  1. Webhook receives event
  2. Code node verifies Stripe signature
  3. IF node checks $json.body.type === "payment_intent.succeeded"
  4. Downstream nodes process the payment (update database, send receipt, etc.)

Example 2: GitHub Push Webhook

Scenario: Trigger deployment when code is pushed to main branch.

Method: POST
Path: /github-deploy
Authentication: Header Auth (X-Hub-Signature-256)
Response: Immediately

Key payload fields:

{{ $json.body.ref }}           // "refs/heads/main"
{{ $json.body.repository.name }} // "my-repo"
{{ $json.body.pusher.name }}   // "developer-name"

Workflow pattern:

  1. Webhook receives push event
  2. IF node checks $json.body.ref === "refs/heads/main"
  3. Execute Command node runs deployment script
  4. Slack node notifies team of deployment status

Example 3: Custom Form Handler

Scenario: Receive form submissions from your website.

Method: POST
Path: /contact-form
Authentication: Header Auth
Response: When Last Node Finishes (return confirmation)

Form posts:

{
  "name": "Jane Doe",
  "email": "[email protected]",
  "message": "Interested in your services",
  "source": "website-footer"
}

Workflow pattern:

  1. Webhook receives submission
  2. Set node formats data
  3. Google Sheets node logs the lead
  4. Email node sends to sales team
  5. Respond to Webhook returns confirmation

Example 4: Chatbot Integration

Scenario: Receive messages from a chat platform (Slack, Discord, custom).

Method: POST
Path: /chatbot
Authentication: Header Auth
Response: Using Respond to Webhook Node

Workflow pattern:

  1. Webhook receives message
  2. AI agent processes the message
  3. Respond to Webhook returns the AI response

For chat integrations, response time matters. Use streaming responses for AI workflows where supported.

Example 5: CRM Update Notifications

Scenario: HubSpot notifies you when a deal stage changes.

Method: POST
Path: /hubspot-deals
Authentication: None (HubSpot does not support custom auth; verify source differently)
Response: Immediately

Workflow pattern:

  1. Webhook receives deal update
  2. IF node checks deal stage and value
  3. High-value deals trigger Slack alert to sales manager
  4. All updates logged to analytics database

Pro Tips and Best Practices

1. Use Descriptive Webhook Paths

Instead of /webhook/a1b2c3d4, use meaningful paths:

/webhook/stripe-payments
/webhook/github-deploys
/webhook/contact-submissions

This makes debugging easier and URLs more readable in external service configurations.

2. Log Incoming Data During Development

Add a Set node after the webhook to capture raw data:

{
  "timestamp": "{{ $now }}",
  "headers": {{ JSON.stringify($json.headers) }},
  "body": {{ JSON.stringify($json.body) }},
  "params": {{ JSON.stringify($json.params) }}
}

Send this to a Google Sheet or database during development to debug payload issues.

3. Always Acknowledge Receipt

External services retry failed webhooks. Return a 200 quickly to prevent duplicate processing:

  • Use “Immediately” response mode for long workflows
  • Process heavy logic asynchronously if needed

4. Handle Idempotency

Many services include an event ID. Store processed IDs and skip duplicates:

const eventId = $json.body.id;
// Check database if eventId was already processed
// Skip if duplicate

5. Monitor Webhook Health

Track webhook executions in n8n’s Executions tab. Look for:

  • Failure patterns (same error recurring)
  • Unusual volume spikes (possible abuse)
  • Timeout trends (workflow too slow)

Set up an Error Trigger workflow to alert you when webhooks fail. For monitoring setup, see our workflow best practices guide.

6. Document Your Endpoints

Keep a record of:

  • Each webhook path and what service uses it
  • Expected payload structure
  • Authentication credentials location
  • Workflow it triggers

This saves hours when debugging or onboarding team members.

For professional help building robust webhook integrations, explore our workflow development services.

Frequently Asked Questions

Why is my webhook not triggering even though I set up the URL correctly?

The most common cause is using the test URL instead of the production URL, or having the workflow deactivated. Test URLs (containing /webhook-test/) only work while you have the n8n editor open and are actively clicking “Listen for Test Event.” For webhooks to work continuously, you must use the production URL (containing /webhook/) and toggle the workflow to Active. Also verify the HTTP method matches what the external service sends. If your webhook expects POST but receives GET, the request fails silently. Enable “Allow Multiple HTTP Methods” in settings if you are unsure which method the service uses.

What is the difference between the Test URL and Production URL?

Test URLs are temporary endpoints that only work during active development in the n8n editor. When you click “Listen for Test Event,” n8n creates a test webhook that stays active for 120 seconds, letting you send test requests and see the data in the editor. Production URLs are permanent endpoints that work when your workflow is activated. They persist even when the editor is closed and are what you should configure in external services like Stripe, GitHub, or Shopify. The URL paths differ slightly: test URLs contain /webhook-test/ while production URLs contain /webhook/.

How do I secure my webhook to prevent unauthorized access?

Never use “None” authentication in production. At minimum, configure Header Auth with a strong secret that callers must include in their requests. For webhooks from major platforms (Stripe, GitHub, Shopify), implement HMAC signature verification using a Code node to cryptographically prove the request came from the legitimate source and was not tampered with. Additional security layers include rate limiting at your reverse proxy, IP allowlisting if the sender publishes their IP ranges, and input validation before processing any data. See our comprehensive webhook security guide for implementation details.

Why am I receiving duplicate webhook events?

Duplicate events typically occur because the sending service retries webhooks when it does not receive a timely 200 response. If your workflow takes too long and times out (n8n Cloud has a 100-second Cloudflare limit), the service assumes delivery failed and sends again. To fix this, use “Immediately” response mode to acknowledge receipt quickly, then process data asynchronously if needed. For platforms like Meta/Instagram that send inherent duplicates, implement idempotency checking by storing processed event IDs and skipping any you have already handled. Also verify you do not have multiple workflows listening on the same webhook path.

How do I respond with custom data or status codes to the webhook caller?

To send custom responses, set the Response mode to “Using ‘Respond to Webhook’ Node” in your Webhook configuration. Then add a Respond to Webhook node anywhere in your workflow after the processing logic. In that node, you can configure the response body (JSON, text, or binary), HTTP status code (200, 201, 400, 500, etc.), and custom headers. This is useful for building API-like endpoints that return processed data, or for returning structured error responses when validation fails. For simple confirmations, “When Last Node Finishes” mode automatically returns the last node’s output without needing a separate response node.

Ready to Automate Your Business?

Tell us what you need automated. We'll build it, test it, and deploy it fast.

48-72 Hour Turnaround
Production Ready
Free Consultation

Create Your Free Account

Sign up once, use all tools free forever. We require accounts to prevent abuse and keep our tools running for everyone.

or

By signing up, you agree to our Terms of Service and Privacy Policy. No spam, unsubscribe anytime.