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 →
{
"name": "AW-1: Demo Build Trigger (Phase 1 - Manual)",
"nodes": [
{
"id": "webhook-trigger",
"name": "Webhook: Close Lead Updated",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
],
"parameters": {
"httpMethod": "POST",
"path": "aw-demo-trigger",
"options": {}
}
},
{
"id": "filter-and-build",
"name": "Code: Filter + Build Payload",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
600,
300
],
"parameters": {
"jsCode": "// \u2500\u2500 Phase 1 manual trigger (idempotent) \u2500\u2500\n// Fire if ALL of:\n// - Demo Send field was in this update's changed_fields\n// - Current Demo Send is \"True\"\n// - cf_demo_sent_at is empty (OR Rebuild is \"Yes\")\n// This avoids the Close-batching edge case where rapid False\u2192True\n// gets de-duped into previous=current=True.\n\nvar webhookBody = $('Webhook: Close Lead Updated').first().json.body || {};\nvar event = webhookBody.event || webhookBody;\nvar webhookData = event.data || {};\nvar changedFields = event.changed_fields || [];\n\nvar lead = $('Close: Get Full Lead').first().json || {};\nvar cf = lead.custom || {};\n\nvar KEY_SEND = 'custom.cf_MuBbV1mNj2o47xuMYhTyVYaqwaqaban5s8wxkeYdvZf';\n\n// 1. Demo Send must have been touched in this update\nvar demoSendTouched = changedFields.indexOf(KEY_SEND) >= 0;\nif (!demoSendTouched) return [];\n\n// 2. Current value must be \"True\" (read from fresh lead, by NAME)\nif (cf['Website Demo - Send'] !== 'True') return [];\n\n// 3. Skip if already sent (unless explicit rebuild)\nvar alreadySent = !!cf['Website Demo - Sent At'];\nvar isRebuild = (cf['Website Demo - Rebuild'] === 'Yes');\nif (alreadySent && !isRebuild) return [];\n\n// 4. Niche normalization \u2014 Google Places categories often use verbose names.\n// Order = MOST SPECIFIC FIRST. \"road construction company\" must be caught\n// before generic \"construction\", and \"dock builder\" before \"deck\" (they\n// share no letters but both are contractor types).\nvar rawNiche = String(cf['Niche'] || '').toLowerCase();\nvar niche = 'plumbing';\n\n// Compound / disambiguating matches (must run before generic ones)\nif (rawNiche.indexOf('road construction') >= 0) niche = 'paving';\nelse if (rawNiche.indexOf('dock builder') >= 0) niche = 'deck-builder';\nelse if (rawNiche.indexOf('excavat') >= 0) niche = 'foundation-repair';\nelse if (rawNiche.indexOf('bathroom remodel') >= 0) niche = 'remodeling';\n\n// Original substring matches\nelse if (rawNiche.indexOf('roof') >= 0) niche = 'roofing';\nelse if (rawNiche.indexOf('hvac') >= 0) niche = 'hvac';\nelse if (rawNiche.indexOf('electric') >= 0) niche = 'electrician';\nelse if (rawNiche.indexOf('landscap') >= 0) niche = 'landscaping';\nelse if (rawNiche.indexOf('tree') >= 0) niche = 'tree-service';\nelse if (rawNiche.indexOf('pool') >= 0) niche = 'pool-installation';\nelse if (rawNiche.indexOf('fenc') >= 0) niche = 'fencing';\nelse if (rawNiche.indexOf('deck') >= 0) niche = 'deck-builder';\nelse if (rawNiche.indexOf('garage') >= 0) niche = 'garage-door';\nelse if (rawNiche.indexOf('septic') >= 0) niche = 'septic-service';\nelse if (rawNiche.indexOf('concrete') >= 0) niche = 'concrete';\nelse if (rawNiche.indexOf('foundation') >= 0) niche = 'foundation-repair';\nelse if (rawNiche.indexOf('pav') >= 0) niche = 'paving';\nelse if (rawNiche.indexOf('press') >= 0) niche = 'pressure-washing';\nelse if (rawNiche.indexOf('junk') >= 0 || rawNiche.indexOf('haul') >= 0) niche = 'junk-removal';\nelse if (rawNiche.indexOf('remodel') >= 0 || rawNiche.indexOf('renov') >= 0) niche = 'remodeling';\nelse if (rawNiche.indexOf('contractor') >= 0) niche = 'general-contractor';\nelse if (rawNiche.indexOf('construction') >= 0) niche = 'general-contractor'; // catches \"Construction company\", \"General Construction\"\nelse if (rawNiche.indexOf('plumb') >= 0) niche = 'plumbing';\n\n// 5. Phone from contacts (lead's real phone)\nvar phone = '';\nif (lead.contacts && lead.contacts.length > 0) {\n for (var i = 0; i < lead.contacts.length; i++) {\n var c = lead.contacts[i];\n if (c.phones && c.phones.length > 0 && c.phones[0].phone) {\n phone = c.phones[0].phone;\n break;\n }\n }\n}\nif (!phone) phone = cf['Send Number'] || '';\nif (!phone) return [];\n\n// 6. City/State/ZIP \u2014 parse Address as fallback\nvar city = cf['City'] || '';\nvar state = cf['State'] || '';\nvar zipCode = cf['ZIP'] || '';\nvar street = '';\nvar fullAddr = String(cf['Address'] || '').trim();\nif ((!city || !state || !zipCode) && fullAddr) {\n var m = fullAddr.match(/^(?:(.+?),\\s*)?([A-Za-z][A-Za-z .'-]+?),\\s*([A-Z]{2})\\s+(\\d{5}(?:-\\d{4})?)/);\n if (m) {\n street = street || m[1] || '';\n city = city || m[2] || '';\n state = state || m[3] || '';\n zipCode = zipCode || m[4] || '';\n } else {\n var loose = fullAddr.match(/^([A-Za-z][A-Za-z .'-]+?),\\s*([A-Z]{2})\\s+(\\d{5})/);\n if (loose) {\n city = city || loose[1] || '';\n state = state || loose[2] || '';\n zipCode = zipCode || loose[3] || '';\n }\n }\n}\nif (!city) return [];\n\nreturn [{\n json: {\n leadId: lead.id,\n niche: niche,\n businessInfo: {\n name: lead.display_name || lead.name,\n phone: phone,\n address: street || fullAddr,\n city: city,\n state: state || 'US',\n zip: zipCode,\n services: [],\n rating: cf['Google Rating'] ? parseFloat(cf['Google Rating']) : undefined,\n reviewCount: cf['Google Reviews'] ? parseInt(cf['Google Reviews']) : undefined\n }\n }\n}];"
}
},
{
"id": "call-build-api",
"name": "HTTP: Build Demo API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
680,
300
],
"parameters": {
"method": "POST",
"url": "=https://YOUR_APP_HOST/api/build-demo",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_API_TOKEN"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify($json) }}",
"options": {
"timeout": 30000
}
}
},
{
"id": "if-success",
"name": "IF: Build Success?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
900,
300
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "cond-success",
"leftValue": "={{ $json.success }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
}
},
{
"id": "send-demo-sms",
"name": "Close: Send Demo SMS",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1320,
200
],
"parameters": {
"method": "POST",
"url": "https://api.close.com/api/v1/activity/sms/",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Basic YOUR_BASIC_AUTH"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"lead_id\": \"{{ $('Code: Filter + Build Payload').first().json.leadId }}\",\n \"local_phone\": \"{{ ($('Close: Get Last Outbound SMS').first().json.data && $('Close: Get Last Outbound SMS').first().json.data.length > 0) ? $('Close: Get Last Outbound SMS').first().json.data[0].local_phone : '+15555550100' }}\",\n \"remote_phone\": \"{{ $('Code: Filter + Build Payload').first().json.businessInfo.phone }}\",\n \"text\": \"More leads More creditability\\n\\n{{ $('HTTP: Build Demo API').first().json.demoUrl }}\\n\\nOnline presence is more important than ever!\\n\\nRemeber this is a demo any text you want changed we can do it!\\n\\nWhat do you think?\",\n \"status\": \"outbox\"\n}"
},
"disabled": false
},
{
"id": "mark-sent",
"name": "Close: Mark Demo Sent",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1540,
200
],
"parameters": {
"method": "PUT",
"url": "=https://api.close.com/api/v1/lead/{{ $('Code: Filter + Build Payload').first().json.leadId }}/",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Basic YOUR_BASIC_AUTH"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"custom.cf_RJaIZqW4kmINDhKvOWUSRe9IZ87VBPFkdGYyzwLSh6w\": \"{{ $now.toISO() }}\",\n \"custom.cf_CLBEEeGPX116lRecdaQX3Zht4Ex0XiCNkLT7BPJlu0Q\": \"{{ $('HTTP: Build Demo API').first().json.slug }}\",\n \"custom.cf_PtpuFWgtGXpYyV5jjv5HOcPIPRulMAKjSgGwwZ4din5\": \"No\",\n \"custom.cf_JJr3nY7RiBitSqZ3ARqmKGGXCH8517mcnL2D8QLKMIn\": \"No\"\n}"
},
"disabled": false
},
{
"id": "log-error",
"name": "NoOp: Log Failure",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1120,
400
],
"parameters": {}
},
{
"id": "get-last-sms",
"name": "Close: Get Last Outbound SMS",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1100,
200
],
"parameters": {
"method": "GET",
"url": "=https://api.close.com/api/v1/activity/sms/?lead_id={{ $('Code: Filter + Build Payload').first().json.leadId }}&direction=outbound&_order_by=-date_created&_limit=1&_fields=id,local_phone,date_created",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Basic YOUR_BASIC_AUTH"
}
]
},
"options": {
"timeout": 15000
}
}
},
{
"id": "get-full-lead",
"name": "Close: Get Full Lead",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
380,
300
],
"parameters": {
"method": "GET",
"url": "=https://api.close.com/api/v1/lead/{{ $('Webhook: Close Lead Updated').first().json.body.event.lead_id }}/",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Basic YOUR_BASIC_AUTH"
}
]
},
"options": {
"timeout": 15000
}
}
},
{
"id": "mark-sms-sent",
"name": "Convex: Mark SMS Sent",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1760,
200
],
"parameters": {
"method": "POST",
"url": "https://YOUR_APP_HOST/api/mark-sms-sent",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_API_TOKEN"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"slug\": \"{{ $('HTTP: Build Demo API').first().json.slug }}\",\n \"smsSentAt\": {{ $now.toMillis() }},\n \"remotePhone\": \"{{ $('Code: Filter + Build Payload').first().json.businessInfo.phone }}\",\n \"localPhone\": \"{{ ($('Close: Get Last Outbound SMS').first().json.data && $('Close: Get Last Outbound SMS').first().json.data.length > 0) ? $('Close: Get Last Outbound SMS').first().json.data[0].local_phone : '+15555550100' }}\"\n}",
"options": {
"timeout": 15000
}
}
}
],
"connections": {
"Webhook: Close Lead Updated": {
"main": [
[
{
"node": "Close: Get Full Lead",
"type": "main",
"index": 0
}
]
]
},
"Close: Get Full Lead": {
"main": [
[
{
"node": "Code: Filter + Build Payload",
"type": "main",
"index": 0
}
]
]
},
"Code: Filter + Build Payload": {
"main": [
[
{
"node": "HTTP: Build Demo API",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Build Demo API": {
"main": [
[
{
"node": "IF: Build Success?",
"type": "main",
"index": 0
}
]
]
},
"IF: Build Success?": {
"main": [
[
{
"node": "Close: Get Last Outbound SMS",
"type": "main",
"index": 0
}
],
[
{
"node": "NoOp: Log Failure",
"type": "main",
"index": 0
}
]
]
},
"Close: Get Last Outbound SMS": {
"main": [
[
{
"node": "Close: Send Demo SMS",
"type": "main",
"index": 0
}
]
]
},
"Close: Send Demo SMS": {
"main": [
[
{
"node": "Convex: Mark SMS Sent",
"type": "main",
"index": 0
}
]
]
},
"Convex: Mark SMS Sent": {
"main": [
[
{
"node": "Close: Mark Demo Sent",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"active": false
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AW-1: Demo Build Trigger (Phase 1 - Manual). Uses httpRequest. Webhook trigger; 10 nodes.
Source: https://github.com/rafiulislam4246/auto-website-sell-workflows/blob/main/workflows/01-demo-build-trigger.json — 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.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.
This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c