Cleaned up all skills to remove research/telemetry context that was used during design but is not needed at runtime when AI agents use the skills. ## Changes Made ### Pattern 1: Research Framing Removed - "From analysis of X workflows/events" → Removed - "From telemetry analysis:" → Replaced with operational context - "Based on X real workflows" → Simplified to general statements ### Pattern 2: Popularity Metrics Removed - "**Popularity**: Second most common (892 templates)" → Removed entirely - "813 searches", "456 templates", etc. → Removed ### Pattern 3: Frequency Percentages Converted - "**Frequency**: 45% of errors" → "Most common error" - "**Frequency**: 28%" → "Second most common" - "**Frequency**: 12%" → "Common error" - Percentages in tables → Priority levels (Highest/High/Medium/Low) ### Pattern 4: Operational Guidance Kept - ✅ Success rates (91.7%) - helps tool selection - ✅ Average times (18s, 56s) - sets expectations - ✅ Relative priority (most common, typical) - guides decisions - ✅ Iteration counts (2-3 cycles) - manages expectations ## Files Modified (19 files across 4 skills) **Skill #2: MCP Tools Expert (5 files)** - Removed telemetry occurrence counts - Kept success rates and average times **Skill #3: Workflow Patterns (7 files)** - Removed all popularity metrics from pattern files - Removed "From analysis of 31,917 workflows" - Removed template counts **Skill #4: Validation Expert (4 files)** - Converted frequency % to priority levels - Removed "From analysis of 19,113 errors" - Removed telemetry loop counts (kept iteration guidance) **Skill #5: Node Configuration (3 files)** - Removed workflow update counts - Removed essentials call counts - Kept success rates and timing guidance ## Result Skills now provide clean, focused runtime guidance without research justification. Content is more actionable for AI agents using the skills. All technical guidance, examples, patterns, and operational metrics preserved. Only removed: research methodology, data source attribution, and statistical justification for design decisions. 🤖 Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
12 KiB
Webhook Processing Pattern
Use Case: Receive HTTP requests from external systems and process them instantly.
Pattern Structure
Webhook → [Validate] → [Transform] → [Action] → [Response/Notify]
Key Characteristic: Instant event-driven processing
Core Components
1. Webhook Node (Trigger)
Purpose: Create HTTP endpoint to receive data
Configuration:
{
path: "form-submit", // URL path: https://n8n.example.com/webhook/form-submit
httpMethod: "POST", // GET, POST, PUT, DELETE
responseMode: "onReceived", // or "lastNode" for custom response
responseData: "allEntries" // or "firstEntryJson"
}
Critical Gotcha: Data is nested under $json.body
❌ {{$json.email}}
✅ {{$json.body.email}}
2. Validation (Optional but Recommended)
Purpose: Verify incoming data before processing
Options:
- IF node - Check required fields exist
- Code node - Custom validation logic
- Stop and Error - Fail gracefully with message
Example:
// IF node condition
{{$json.body.email}} is not empty AND
{{$json.body.name}} is not empty
3. Transformation
Purpose: Map webhook data to desired format
Typical nodes:
- Set - Field mapping
- Code - Complex transformations
Example (Set node):
{
"user_email": "={{$json.body.email}}",
"user_name": "={{$json.body.name}}",
"timestamp": "={{$now}}"
}
4. Action
Purpose: Do something with the data
Common actions:
- Store in database (Postgres, MySQL, MongoDB)
- Send notification (Slack, Email, Discord)
- Call another API (HTTP Request)
- Update external system (CRM, support ticket)
5. Response (If responseMode: "lastNode")
Purpose: Send custom HTTP response
Webhook Response Node:
{
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: {
"status": "success",
"message": "Form received"
}
}
Common Use Cases
1. Form Submissions
Flow: Form → Webhook → Validate → Database → Email Confirmation
Example:
1. Webhook (path: "contact-form", POST)
2. IF (check email & message not empty)
3. Postgres (insert into contacts table)
4. Email (send confirmation to user)
5. Slack (notify team in #leads)
6. Webhook Response ({"status": "success"})
Real Data Access:
Name: {{$json.body.name}}
Email: {{$json.body.email}}
Message: {{$json.body.message}}
2. Payment Webhooks (Stripe, PayPal)
Flow: Payment Provider → Webhook → Verify → Update Database → Send Receipt
Security: Verify webhook signatures
// Code node - verify Stripe signature
const crypto = require('crypto');
const signature = $input.item.headers['stripe-signature'];
const secret = $credentials.stripeWebhookSecret;
// Verify signature matches
const expectedSig = crypto
.createHmac('sha256', secret)
.update($input.item.body)
.digest('hex');
if (signature !== expectedSig) {
throw new Error('Invalid webhook signature');
}
return $input.item.body; // Return validated body
3. Chat Platform Integrations (Slack, Discord, Teams)
Flow: Chat Command → Webhook → Process → Respond
Example (Slack slash command):
1. Webhook (path: "slack-command", POST)
2. Code (parse Slack payload: $json.body.text, $json.body.user_id)
3. HTTP Request (fetch data from API)
4. Set (format Slack message)
5. Webhook Response (immediate Slack response)
Slack Data Access:
Command: {{$json.body.command}}
Text: {{$json.body.text}}
User ID: {{$json.body.user_id}}
Channel ID: {{$json.body.channel_id}}
4. GitHub/GitLab Webhooks
Flow: Git Event → Webhook → Parse → Notify/Deploy
Example (new PR notification):
1. Webhook (path: "github", POST)
2. IF (check $json.body.action equals "opened")
3. Set (extract PR details: title, author, url)
4. Slack (notify #dev-team)
5. Webhook Response (200 OK)
GitHub Data Access:
Event Type: {{$json.headers['x-github-event']}}
Action: {{$json.body.action}}
PR Title: {{$json.body.pull_request.title}}
Author: {{$json.body.pull_request.user.login}}
URL: {{$json.body.pull_request.html_url}}
5. IoT Device Data
Flow: Device → Webhook → Validate → Store → Alert (if threshold)
Example (temperature sensor):
1. Webhook (path: "sensor-data", POST)
2. Set (extract sensor readings)
3. Postgres (insert into sensor_readings)
4. IF (temperature > 80)
5. Email (alert admin)
Webhook Data Structure
Standard Structure
{
"headers": {
"content-type": "application/json",
"user-agent": "...",
"x-custom-header": "..."
},
"params": {
"id": "123" // From URL: /webhook/form/:id
},
"query": {
"token": "abc" // From URL: /webhook/form?token=abc
},
"body": {
// ⚠️ YOUR DATA IS HERE!
"name": "John",
"email": "john@example.com"
}
}
Accessing Different Parts
// Headers
{{$json.headers['content-type']}}
{{$json.headers['x-api-key']}}
// URL Parameters
{{$json.params.id}}
// Query Parameters
{{$json.query.token}}
{{$json.query.page}}
// Body (MOST COMMON)
{{$json.body.email}}
{{$json.body.user.name}}
{{$json.body.items[0].price}}
Authentication & Security
1. Query Parameter Token
Simple but less secure
// IF node - validate token
{{$json.query.token}} equals "your-secret-token"
2. Header-Based Auth
Better security
// IF node - check header
{{$json.headers['x-api-key']}} equals "your-api-key"
3. Signature Verification
Best security (for webhooks from services like Stripe, GitHub)
// Code node
const crypto = require('crypto');
const signature = $input.item.headers['x-signature'];
const secret = $credentials.webhookSecret;
const calculatedSig = crypto
.createHmac('sha256', secret)
.update(JSON.stringify($input.item.body))
.digest('hex');
if (signature !== `sha256=${calculatedSig}`) {
throw new Error('Invalid signature');
}
return $input.item.body;
4. IP Whitelist
Restrict access by IP (n8n workflow settings)
- Configure in workflow settings
- Only allow specific IP ranges
- Use for internal systems
Response Modes
onReceived (Default)
Behavior: Immediate 200 OK response, workflow continues in background
Use when:
- Long-running workflows
- Response doesn't depend on workflow result
- Fire-and-forget processing
Configuration:
{
responseMode: "onReceived",
responseCode: 200
}
lastNode (Custom Response)
Behavior: Wait for workflow completion, send custom response
Use when:
- Need to return data to caller
- Synchronous processing required
- Form submissions with confirmation
Configuration:
{
responseMode: "lastNode"
}
Then add Webhook Response node:
{
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: {
"id": "={{$json.record_id}}",
"status": "success"
}
}
Error Handling
Pattern 1: Try-Catch with Error Trigger
Main Flow:
Webhook → [nodes...] → Success Response
Error Flow:
Error Trigger → Log Error → Slack Alert → Error Response
Error Trigger Configuration:
{
workflowId: "current-workflow-id"
}
Error Response (if responseMode: "lastNode"):
{
statusCode: 500,
body: {
"status": "error",
"message": "Processing failed"
}
}
Pattern 2: Validation Early Exit
Webhook → IF (validate) → [True: Process]
└→ [False: Error Response]
False Branch Response:
{
statusCode: 400,
body: {
"status": "error",
"message": "Invalid data: missing email"
}
}
Pattern 3: Continue On Fail
Per-node setting: Continue even if node fails
Use case: Non-critical notifications
Webhook → Database (critical) → Slack (continueOnFail: true)
Testing Webhooks
1. Use Manual Trigger
Replace Webhook with Manual Trigger for testing:
Manual Trigger → [set test data] → rest of workflow
2. Use curl
curl -X POST https://n8n.example.com/webhook/form-submit \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "name": "Test User"}'
3. Use Postman/Insomnia
- Create request collection
- Test different payloads
- Verify responses
4. Webhook.site
- Use webhook.site for testing
- Copy webhook.site URL to your service
- View requests and debug
Performance Considerations
Large Payloads
- Webhook timeout: 120 seconds (default)
- For large data, consider async processing:
Webhook → Queue (Redis/DB) → Response (immediate) Separate Workflow: Schedule → Check Queue → Process
High Volume
- Use "Execute Once" mode if processing all items together
- Consider rate limiting
- Monitor execution times
- Scale n8n instance if needed
Retries
- Webhook calls typically don't retry automatically
- Implement retry logic on caller side
- Or use queue pattern for guaranteed processing
Common Gotchas
1. ❌ Wrong: Accessing webhook data
{{$json.email}} // Empty or undefined
✅ Correct
{{$json.body.email}} // Data is under .body
2. ❌ Wrong: Response mode confusion
Using Webhook Response node with responseMode: "onReceived" (ignored)
✅ Correct
Set responseMode: "lastNode" to use Webhook Response node
3. ❌ Wrong: No validation
Assuming data is always present and valid
✅ Correct
Validate data early with IF node or Code node
4. ❌ Wrong: Hardcoded paths
Using same path for dev/prod
✅ Correct
Use environment variables: {{$env.WEBHOOK_PATH_PREFIX}}/form-submit
Real Template Examples
From n8n template library (1,085 webhook templates):
Simple Form to Slack:
Webhook → Set → Slack
Payment Processing:
Webhook → Verify Signature → Update Database → Send Receipt → Notify Admin
Chat Bot:
Webhook → Parse Command → AI Agent → Format Response → Webhook Response
Use search_templates({query: "webhook"}) to find more!
Checklist for Webhook Workflows
Setup
- Choose descriptive webhook path
- Configure HTTP method (POST most common)
- Choose response mode (onReceived vs lastNode)
- Test webhook URL before connecting services
Security
- Add authentication (token, signature, IP whitelist)
- Validate incoming data
- Sanitize user input (if storing/displaying)
- Use HTTPS (always)
Data Handling
- Remember data is under $json.body
- Handle missing fields gracefully
- Transform data to desired format
- Log important data (for debugging)
Error Handling
- Add Error Trigger workflow
- Validate required fields
- Return appropriate error responses
- Alert team on failures
Testing
- Test with curl/Postman
- Test error scenarios
- Verify response format
- Monitor first executions
Summary
Key Points:
- Data under $json.body (most common mistake!)
- Validate early to catch bad data
- Choose response mode based on use case
- Secure webhooks with auth
- Handle errors gracefully
Pattern: Webhook → Validate → Transform → Action → Response
Related:
- n8n Expression Syntax - Accessing webhook data correctly
- http_api_integration.md - Making HTTP requests in response