This workflow corresponds to n8n.io template #13850 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"nodes": [
{
"id": "1c8e06b1-4e77-4271-bd2f-b37ca3a8ff63",
"name": "Respond - Validation Error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1200,
432
],
"parameters": {
"options": {
"responseCode": 400
},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ status: 'error', errors: $json.validationErrors }) }}"
},
"typeVersion": 1.1
},
{
"id": "64df2cf2-fd02-4323-9bbf-39fb991905cb",
"name": "Invalid Lead - Error Handler",
"type": "n8n-nodes-base.code",
"position": [
960,
432
],
"parameters": {
"jsCode": "const lead = $input.first().json;\nconst errors = [];\nif (!lead.email || !lead.email.includes('@')) errors.push('Missing or invalid email');\nif (!lead.name) errors.push('Missing name');\nif (!lead.message) errors.push('Missing message');\nreturn { json: { ...lead, isValid: false, validationErrors: errors, processedAt: new Date().toISOString() } };"
},
"typeVersion": 2
},
{
"id": "295405dc-b38a-4dee-ac40-4c2a804d8b4c",
"name": "Valid Lead - Ready for AI",
"type": "n8n-nodes-base.code",
"position": [
960,
208
],
"parameters": {
"jsCode": "const lead = $input.first().json;\nreturn { json: { ...lead, isValid: true, processedAt: new Date().toISOString(), readyForAI: true } };"
},
"typeVersion": 2
},
{
"id": "425f8875-f544-428c-ad3c-075074b4f30f",
"name": "Validate Required Fields",
"type": "n8n-nodes-base.if",
"position": [
720,
304
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "valid-check",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.isValid }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f262f8fa-c102-4292-b50e-3a082ac4a1ec",
"name": "Normalize Input Data",
"type": "n8n-nodes-base.code",
"position": [
480,
304
],
"parameters": {
"jsCode": "// Normalize incoming lead data\nconst raw = $input.first().json.body;\n\nconst normalized = {\n name: (raw.fullName || raw.name || raw.full_name || '').trim(),\n email: (raw.email || raw.emailAddress || raw.email_address || '').toLowerCase().trim(),\n company: (raw.company || raw.organization || raw.org || 'Unknown').trim(),\n message: (raw.message || raw.body || raw.content || raw.inquiry || '').trim(),\n source: (raw.source || raw.utm_source || 'web').toLowerCase(),\n receivedAt: new Date().toISOString()\n};\n\n// Validate required fields\nnormalized.isValid = !!(normalized.email && normalized.email.includes('@') && normalized.name && normalized.message);\n\nreturn { json: normalized };"
},
"typeVersion": 2
},
{
"id": "4791bc46-202c-46f9-8603-322ecab261c6",
"name": "Webhook - Receive Lead Data",
"type": "n8n-nodes-base.webhook",
"position": [
256,
304
],
"parameters": {
"path": "incoming-lead",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "c94f5731-4fc2-4524-9f2f-563f41c09275",
"name": "Respond - Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1200,
208
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ status: 'received', valid: true }) }}"
},
"typeVersion": 1.1
},
{
"id": "5ec1b0e0-f652-4f37-ac4d-4683a8221ce8",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
16
],
"parameters": {
"width": 560,
"height": 736,
"content": "## Input Normalization + Validation\n\n### How it works\n1. **Webhook** receives raw lead data via POST request.\n2. **Normalize Input Data** (Code node) standardizes field names, trims whitespace, lowercases emails, and flattens inconsistent payloads into a clean object.\n3. **Validate Required Fields** (IF node) checks that email is valid and message is non-empty. Valid leads continue; invalid leads route to error handling.\n4. **Valid Lead** path packages the cleaned data, ready for downstream AI processing. **Invalid Lead** path returns a structured error response listing which fields failed.\n\n### Setup\n- Import the template and open the **Webhook** node to copy its test URL\n- Use a tool like curl or Postman to send a POST request with JSON lead data (fields: name, email, company, message)\n- Inspect the **Normalize Input Data** code node to customize field mappings for your data sources\n\n### Customization\n- Add more validation rules in the IF node (e.g., check company against a known list)\n- Extend normalization to handle additional input formats or sources\n- Connect the Valid Lead output to your AI classification or enrichment workflow\n\nThis template is a learning companion to the Production AI Playbook, a series that explores strategies, shares best practices, and provides practical examples for building reliable AI systems in n8n. \n\nhttps://go.n8n.io/PAP-D&A-Blog"
},
"typeVersion": 1
},
{
"id": "955fe6f5-e602-45ed-9f06-a1124c65ed7a",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
192,
128
],
"parameters": {
"color": 7,
"width": 432,
"height": 464,
"content": "## Receive & Normalize"
},
"typeVersion": 1
},
{
"id": "77c759da-4cbc-4b5f-84ee-a687992be72c",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
656,
128
],
"parameters": {
"color": 7,
"width": 752,
"height": 464,
"content": "## Validate"
},
"typeVersion": 1
}
],
"connections": {
"Normalize Input Data": {
"main": [
[
{
"node": "Validate Required Fields",
"type": "main",
"index": 0
}
]
]
},
"Validate Required Fields": {
"main": [
[
{
"node": "Valid Lead - Ready for AI",
"type": "main",
"index": 0
}
],
[
{
"node": "Invalid Lead - Error Handler",
"type": "main",
"index": 0
}
]
]
},
"Valid Lead - Ready for AI": {
"main": [
[
{
"node": "Respond - Success",
"type": "main",
"index": 0
}
]
]
},
"Webhook - Receive Lead Data": {
"main": [
[
{
"node": "Normalize Input Data",
"type": "main",
"index": 0
}
]
]
},
"Invalid Lead - Error Handler": {
"main": [
[
{
"node": "Respond - Validation Error",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Clean and validate incoming data before it ever reaches an AI step. This template takes raw webhook data, normalizes inconsistent field names and formats, and routes invalid inputs to error handling.
Source: https://n8n.io/workflows/13850/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
A production-ready authentication workflow implementing secure user registration, login, token verification, and refresh token mechanisms. Perfect for adding authentication to any application without
Portfolio Orchestrator. Uses httpRequest. Webhook trigger; 59 nodes.
This n8n template demonstrates how a simple Multi-Layer Perceptron (MLP) neural network can predict housing prices. The prediction is based on four key features, processed through a three-layer model.
github code Try yourself
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.