{
  "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
          }
        ]
      ]
    }
  }
}