This workflow corresponds to n8n.io template #15630 — 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 →
{
"id": "TD0LsjPaGHjbO3LM",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Precision Form Router & Validater",
"tags": [],
"nodes": [
{
"id": "16dfd0c1-39c8-48d7-94c4-a9c492679a44",
"name": "README",
"type": "n8n-nodes-base.stickyNote",
"position": [
256,
4944
],
"parameters": {
"width": 640,
"height": 420,
"content": "# Precision Form Router & Validater \n\n## How it works\n1. **Trigger**: Captures inbound form submissions via Tally webhook.\n2. **Format**: Extracts complex nested arrays into clean key-value pairs.\n3. **Validate**: Acts as a firewall, using Regex to drop malformed email addresses.\n4. **Route**: Evaluates the requested service tier and deterministically routes the prospect.\n5. **Execute**: Sends parallel internal alerts and tailored customer emails (with a catch-all fallback).\n\n## Setup steps\n- [ ] Connect your SMTP/Email Credentials in n8n\n- [ ] Update `hello@yourdomain.com` and `admin@yourdomain.com` placeholders\n- [ ] Customize the HTML email templates for your specific offerings\n- [ ] Copy the Webhook URL and paste it into your Tally form settings"
},
"typeVersion": 1
},
{
"id": "b9beec46-4e3d-4427-b931-256c5da36578",
"name": "Sticky Note - Section 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
992,
5024
],
"parameters": {
"color": 7,
"width": 840,
"height": 260,
"content": "### Ingestion & Validation\nListens for the Tally webhook. The custom JS Code node extracts deeply nested multi-choice values. The IF node acts as a Regex firewall to validate email syntax."
},
"typeVersion": 1
},
{
"id": "eda0f04b-10b6-4d8e-92c9-9f008ed176a6",
"name": "Sticky Note - Section 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1984,
4304
],
"parameters": {
"color": 7,
"width": 726,
"height": 852,
"content": "### Deterministic Routing & External Comms\nEvaluates the selected tier and routes to the matching email branch. Unmapped tiers are safely routed to the Fallback branch. Nodes continue on fail."
},
"typeVersion": 1
},
{
"id": "5a86a183-8d99-4fed-92c9-1f556956e50c",
"name": "Sticky Note - Section 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1984,
5184
],
"parameters": {
"color": 7,
"width": 726,
"height": 414,
"content": "### Internal Comms & Webhook Closure\nFires an internal lead notification in parallel. Finally, responds to the originating webhook with a 200 Success or a JSON Error payload."
},
"typeVersion": 1
},
{
"id": "625c6177-bc0d-411f-8fb8-5695d76003d3",
"name": "Form Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
1040,
5136
],
"parameters": {
"path": "your-form-path",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "77614242-1cec-491e-96c9-17925d845c55",
"name": "Format Tally Data",
"type": "n8n-nodes-base.code",
"position": [
1264,
5136
],
"parameters": {
"jsCode": "// Get all fields from the webhook\nconst fields = $input.item.json.body.data.fields || [];\n\nfunction getReadableValue(field) {\n if (field.type === 'MULTIPLE_CHOICE' && field.options && field.value) {\n const selectedId = field.value[0];\n const matchingOption = field.options.find(opt => opt.id === selectedId);\n return matchingOption ? matchingOption.text : field.value[0];\n }\n return field.value;\n}\n\nconst mappedData = {\n name: '',\n email: '',\n company: '',\n tier: '',\n allFieldsText: '',\n challenge: 'Not provided'\n};\n\nfields.forEach(field => {\n const label = field.label ? field.label.toLowerCase() : '';\n \n if (label.includes('name') && !label.includes('company')) {\n mappedData.name = field.value;\n }\n if (field.type === 'INPUT_EMAIL') {\n mappedData.email = field.value;\n }\n if (label.includes('company')) {\n mappedData.company = field.value;\n }\n if (field.label === 'tier') {\n mappedData.tier = field.value;\n }\n if (field.type === 'TEXTAREA' && field.value) {\n mappedData.challenge = field.value;\n }\n});\n\nconst allFieldsArray = [];\nfields.forEach(field => {\n if (field.type !== 'HIDDEN_FIELDS' && field.value !== null) {\n const readableValue = getReadableValue(field);\n allFieldsArray.push(`${field.label}: ${readableValue}`);\n }\n});\n\nmappedData.allFieldsText = allFieldsArray.join('\\n');\n\nreturn {\n json: mappedData\n};"
},
"typeVersion": 2
},
{
"id": "8702b28f-ff80-4fe4-a2eb-c354fdc56d01",
"name": "Extract Form Data",
"type": "n8n-nodes-base.set",
"position": [
1488,
5136
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "name",
"name": "name",
"type": "string",
"value": "={{ $json.name }}"
},
{
"id": "email",
"name": "email",
"type": "string",
"value": "={{ $json.email }}"
},
{
"id": "company",
"name": "company",
"type": "string",
"value": "={{ $json.company }}"
},
{
"id": "tier",
"name": "tier",
"type": "string",
"value": "={{ $json.tier }}"
},
{
"id": "allFields",
"name": "allFields",
"type": "string",
"value": "={{ $json.allFieldsText }}"
},
{
"id": "challenge",
"name": "challenge",
"type": "string",
"value": "={{ $json.challenge }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "013fd4e8-70b5-4c7f-87b9-dd02cd0b3a72",
"name": "Validate Lead",
"type": "n8n-nodes-base.if",
"position": [
1712,
5136
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "val1",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.email }}",
"rightValue": ""
},
{
"id": "val2",
"operator": {
"type": "string",
"operation": "regex"
},
"leftValue": "={{ $json.email }}",
"rightValue": "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "328ce3cd-0300-417e-8118-969191a60c81",
"name": "Switch by Service Tier",
"type": "n8n-nodes-base.switch",
"position": [
2080,
4656
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r1",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.tier }}",
"rightValue": "Audit"
}
]
}
},
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r2",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.tier }}",
"rightValue": "Implementation"
}
]
}
},
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r3",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.tier }}",
"rightValue": "Managed Services"
}
]
}
},
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "r4",
"operator": {
"type": "string",
"operation": "regex"
},
"leftValue": "={{ $json.tier }}",
"rightValue": ".*"
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.1
},
{
"id": "fc4b7df8-dc4a-45ec-b342-2730c932f056",
"name": "Email - Audit",
"type": "n8n-nodes-base.emailSend",
"onError": "continueErrorOutput",
"position": [
2304,
4400
],
"parameters": {
"html": "=<!DOCTYPE html>\n<html>\n<body>\n <div class=\"container\">\n <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n <p>Thanks for your inquiry about an <strong>Audit</strong>.</p>\n <p>We've received your message and will get back to you shortly.</p>\n <p>Best regards,<br><strong>Your Team</strong></p>\n </div>\n</body>\n</html>",
"options": {},
"subject": "Thanks for your inquiry - {{ $json.company }}",
"toEmail": "={{ $json.email }}",
"fromEmail": "user@example.com"
},
"typeVersion": 2.1
},
{
"id": "479d271b-ec6c-4377-8bb5-8c469c4c1952",
"name": "Email - Implementation",
"type": "n8n-nodes-base.emailSend",
"onError": "continueErrorOutput",
"position": [
2304,
4592
],
"parameters": {
"html": "=<!DOCTYPE html>\n<html>\n<body>\n <div class=\"container\">\n <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n <p>Thanks for your interest in our <strong>Implementation</strong> services.</p>\n <p>We've received your message and will get back to you shortly.</p>\n <p>Best regards,<br><strong>Your Team</strong></p>\n </div>\n</body>\n</html>",
"options": {},
"subject": "Thanks for your inquiry - {{ $json.company }}",
"toEmail": "={{ $json.email }}",
"fromEmail": "user@example.com"
},
"typeVersion": 2.1
},
{
"id": "b80a9d76-2beb-440f-8953-9e50c47128f4",
"name": "Email - Managed Services",
"type": "n8n-nodes-base.emailSend",
"onError": "continueErrorOutput",
"position": [
2304,
4784
],
"parameters": {
"html": "=<!DOCTYPE html>\n<html>\n<body>\n <div class=\"container\">\n <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n <p>Thanks for your interest in our <strong>Managed Services</strong>.</p>\n <p>We've received your message and will get back to you shortly.</p>\n <p>Best regards,<br><strong>Your Team</strong></p>\n </div>\n</body>\n</html>",
"options": {},
"subject": "Thanks for your inquiry - {{ $json.company }}",
"toEmail": "={{ $json.email }}",
"fromEmail": "user@example.com"
},
"typeVersion": 2.1
},
{
"id": "ee514e74-9211-4f71-9e05-2fd2847e5236",
"name": "Email - Generic/Fallback",
"type": "n8n-nodes-base.emailSend",
"onError": "continueErrorOutput",
"position": [
2304,
4976
],
"parameters": {
"html": "=<!DOCTYPE html>\n<html>\n<body>\n <div class=\"container\">\n <h2>Hi {{ $json.name.split(' ')[0] }},</h2>\n <p>Thanks for your inquiry.</p>\n <p>We've received your message and will get back to you shortly.</p>\n <p>Best regards,<br><strong>Your Team</strong></p>\n </div>\n</body>\n</html>",
"options": {},
"subject": "Thanks for your inquiry - {{ $json.company }}",
"toEmail": "={{ $json.email }}",
"fromEmail": "user@example.com"
},
"typeVersion": 2.1
},
{
"id": "f090f7ab-8406-4fc1-a483-2aa6a94da2d0",
"name": "Notify Internal Team",
"type": "n8n-nodes-base.emailSend",
"onError": "continueErrorOutput",
"position": [
2208,
5296
],
"parameters": {
"html": "=<h2>\ud83c\udfaf New Lead Notification</h2>\n<p><strong>Name:</strong> {{ $json.name }}</p>\n<p><strong>Email:</strong> {{ $json.email }}</p>\n<p><strong>Company:</strong> {{ $json.company }}</p>\n<p><strong>Tier:</strong> {{ $json.tier }}</p>\n<p><strong>Challenge:</strong> {{ $json.challenge }}</p>",
"options": {},
"subject": "=\ud83c\udfaf New {{ $json.tier.toUpperCase() }} Lead - {{ $json.company }}",
"toEmail": "user@example.com",
"fromEmail": "user@example.com"
},
"typeVersion": 2.1
},
{
"id": "85112e07-e297-40a0-a47e-990dd4fd954b",
"name": "Success Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2464,
5280
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"success\": true } }}"
},
"typeVersion": 1.1
},
{
"id": "e02171b5-c3ad-4655-83ec-8aef33987166",
"name": "Error Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2208,
5456
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"success\": false, \"error\": \"Invalid email format provided\" } }}"
},
"typeVersion": 1.1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "67739cf2-57ae-4a0c-901b-e5fe0c7dc8e5",
"connections": {
"Form Webhook": {
"main": [
[
{
"node": "Format Tally Data",
"type": "main",
"index": 0
}
]
]
},
"Validate Lead": {
"main": [
[
{
"node": "Switch by Service Tier",
"type": "main",
"index": 0
},
{
"node": "Notify Internal Team",
"type": "main",
"index": 0
}
],
[
{
"node": "Error Response",
"type": "main",
"index": 0
}
]
]
},
"Extract Form Data": {
"main": [
[
{
"node": "Validate Lead",
"type": "main",
"index": 0
}
]
]
},
"Format Tally Data": {
"main": [
[
{
"node": "Extract Form Data",
"type": "main",
"index": 0
}
]
]
},
"Notify Internal Team": {
"main": [
[
{
"node": "Success Response",
"type": "main",
"index": 0
}
]
]
},
"Switch by Service Tier": {
"main": [
[
{
"node": "Email - Audit",
"type": "main",
"index": 0
}
],
[
{
"node": "Email - Implementation",
"type": "main",
"index": 0
}
],
[
{
"node": "Email - Managed Services",
"type": "main",
"index": 0
}
],
[
{
"node": "Email - Generic/Fallback",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
For specialized B2B agencies, consultancies, and MSPs, lead routing isn't about guessing "purchasing temperature" it’s about distinct operational tracks. An "Infrastructure Audit" requires vastly different triage than a "Managed Services" request. This workflow acts as a…
Source: https://n8n.io/workflows/15630/ — 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.
Ad agencies needing automated lead capture. Sales teams fighting fraud and scoring leads. B2B SaaS companies nurturing prospects. Marketing pros boosting sales pipelines. Captures leads via Webhook fr
Store leads in a SQL Server database via REST API with automatic scoring and Slack notifications.
This n8n workflow automatically captures LinkedIn leads from multiple sources (new connections, post engagements), enriches the data with AI-powered scoring, eliminates duplicates, syncs to Google She
Create records in Odoo from any webform via a secure webhook. The workflow validates required fields, resolves UTMs by name (source, medium, campaign) and writes standard lead fields in Odoo. Clean, p
This workflow captures raw lead data from a Webhook and formats it into a clean, structured object — perfectly tailored for Odoo CRM and create lead. It supports Odoo versions 15, 16, 17, and 18, both