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": "CRM Audit \u2014 Bot vs Didar (Bale)",
"nodes": [
{
"id": "trigger",
"name": "Manual Trigger",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
250,
500
],
"parameters": {}
},
{
"id": "config",
"name": "Config",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
500,
500
],
"parameters": {
"jsCode": "\nconst CONFIG = {\n DIDAR_API_KEY: '1t31qjd4bl43cxej1yybhr2uf24ael2a',\n PIPELINE_ID: '9b0e5024-4822-4833-abe6-8ca426a937ae',\n COMPANY_ID: '00000000-0000-0000-0000-000000000000',\n\n STAGES: {\n register: 'b7e97097-ff9b-4207-a2e7-07dd2ea606af',\n lesson_1: 'ffa64a67-02e0-462b-a0c2-60c85eee6af5',\n lesson_2: 'bcfe1289-12bf-4ee6-88e7-2dcf0ed48469',\n lesson_3: '4223a51c-544b-41e2-94bc-1e99016fbaba',\n lesson_4: '09856491-6d78-40df-b3ed-c80083e77a8f',\n lesson_5: '0fcb3769-e1ad-45d5-8847-e51e97065d85',\n lesson_6: 'aee7d1c1-5f18-43e8-b1cb-050d59ce3517',\n lesson_7: 'd9fc8133-052f-465b-9289-4211272b6e18',\n lesson_8: '6faab0b4-be10-478d-9655-bf41eca744a8',\n sales_wait: '6faab0b4-be10-478d-9655-bf41eca744a8',\n followup_1: 'be5d2b7a-4cf6-4b5d-873f-a3a76ccf2310',\n followup_2: 'daa24b66-5151-4e57-b08e-032a2961c339',\n followup_3: '3d3cf5e9-0726-43db-9e01-885c50c3b2bd',\n won: ''\n },\n\n CUSTOM_FIELDS: {\n monthly_income: 'Field_996_0_26',\n staff_count: 'Field_996_0_25',\n job: 'J',\n best_call_time: 'Field_996_0_31',\n lead_score: 'Field_996_12_30',\n city: 'Field_996_0_11',\n income_class: ''\n },\n\n BOT_PANEL_URL: 'http://195.177.255.133:8080',\n BOT_ADMIN_USER: 'admin',\n BOT_ADMIN_PASS: 'BaleAdmin@2024Panel',\n};\n\n// Build reverse stage lookup: GUID \u2192 stage name\nconst stageToName = {};\nfor (const [name, guid] of Object.entries(CONFIG.STAGES)) {\n stageToName[guid] = name;\n}\nCONFIG._stageToName = stageToName;\n\n// Build lesson_number \u2192 stage GUID mapping\nconst lessonToStage = {};\nfor (const [name, guid] of Object.entries(CONFIG.STAGES)) {\n const m = name.match(/^lesson_(\\d+)$/);\n if (m) lessonToStage[parseInt(m[1])] = guid;\n}\nCONFIG._lessonToStage = lessonToStage;\n\nreturn [{json: {CONFIG}}];\n",
"mode": "runOnceForAllItems"
}
},
{
"id": "login",
"name": "Login Bot Panel",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
750,
500
],
"parameters": {
"method": "POST",
"url": "={{ $json.CONFIG.BOT_PANEL_URL + '/api/auth/login' }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({username: $json.CONFIG.BOT_ADMIN_USER, password: $json.CONFIG.BOT_ADMIN_PASS}) }}",
"options": {
"timeout": 15000
}
}
},
{
"id": "extract_token",
"name": "Extract Token",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
1000,
500
],
"parameters": {
"jsCode": "\nconst config = $('Config').first().json.CONFIG;\nconst resp = $input.first().json;\nconst token = resp.access_token || '';\nif (!token) throw new Error('Login failed \u2014 no access_token in response');\nreturn [{json: {CONFIG: config, token}}];\n",
"mode": "runOnceForAllItems"
}
},
{
"id": "fetch_bot_users",
"name": "Fetch Bot Users",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1250,
500
],
"parameters": {
"method": "GET",
"url": "={{ $json.CONFIG.BOT_PANEL_URL + '/api/audit/users' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.token }}"
}
]
},
"options": {
"timeout": 30000
}
}
},
{
"id": "extract_bot_users",
"name": "Extract Bot Users",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
1500,
500
],
"parameters": {
"jsCode": "\nconst config = $('Config').first().json.CONFIG;\nconst token = $('Extract Token').first().json.token;\nconst resp = $input.first().json;\nconst botUsers = resp.items || [];\nreturn [{json: {CONFIG: config, token, botUsers, totalBotUsers: botUsers.length}}];\n",
"mode": "runOnceForAllItems"
}
},
{
"id": "fetch_deals",
"name": "Fetch Didar Deals",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1750,
500
],
"parameters": {
"method": "POST",
"url": "={{ 'https://app.didar.me/api/deal/search_v2?apikey=' + $json.CONFIG.DIDAR_API_KEY }}",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({Criteria: {PipelineId: $json.CONFIG.PIPELINE_ID}, From: 0, Limit: 5000}) }}",
"options": {
"timeout": 60000
}
}
},
{
"id": "compare",
"name": "Compare & Audit",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
2100,
500
],
"parameters": {
"jsCode": "\n// Gather inputs\nconst data = $('Extract Bot Users').first().json;\nconst CONFIG = data.CONFIG;\nconst botUsers = data.botUsers || [];\n\nconst dealsResp = $('Fetch Didar Deals').first().json;\nconst deals = dealsResp?.Response?.List || dealsResp?.search_respons?.List || [];\n\n// \u2500\u2500 Build lookup maps \u2500\u2500\n\n// Normalise phone: remove leading 0, keep last 10 digits\nfunction normalisePhone(raw) {\n if (!raw) return '';\n const digits = String(raw).replace(/\\D/g, '');\n if (digits.length >= 10) return digits.slice(-10);\n return digits;\n}\n\n// Build deal lookup by person phone (using embedded Person data)\nconst dealByPhone = {};\nconst personByPhone = {};\nfor (const d of deals) {\n const person = d.Person || d.Contact || {};\n const phones = [person.MobilePhone, person.WorkPhone, person.Phone, person.HomePhone].filter(Boolean);\n for (const ph of phones) {\n const norm = normalisePhone(ph);\n if (norm) {\n // Prefer Pending deals; if multiple, keep first pending\n if (!dealByPhone[norm] || d.Status === 'Pending') {\n dealByPhone[norm] = d;\n }\n if (!personByPhone[norm]) {\n personByPhone[norm] = person;\n }\n }\n }\n}\n\n// Stage name from GUID lookup\nconst stageToName = CONFIG._stageToName || {};\nconst lessonToStage = CONFIG._lessonToStage || {};\n\n// \u2500\u2500 Build expected stage for each user \u2500\u2500\nfunction expectedStage(user) {\n if (user.is_completed) return {name: 'won', guid: CONFIG.STAGES.won};\n const ln = user.current_lesson_number;\n if (ln && lessonToStage[ln]) {\n return {name: 'lesson_' + ln, guid: lessonToStage[ln]};\n }\n return {name: 'register', guid: CONFIG.STAGES.register};\n}\n\n// \u2500\u2500 Compare each bot user \u2500\u2500\nconst report = {\n summary: {\n total_bot_users: botUsers.length,\n users_with_phone: 0,\n users_without_phone: 0,\n total_crm_deals: deals.length,\n deal_found: 0,\n deal_missing: 0,\n stage_match: 0,\n stage_mismatch: 0,\n status_match: 0,\n status_mismatch: 0,\n lead_score_match: 0,\n lead_score_mismatch: 0,\n fully_synced: 0,\n },\n missing_deals: [],\n stage_mismatches: [],\n status_mismatches: [],\n lead_score_mismatches: [],\n orphan_deals: [],\n};\n\nconst matchedPhones = new Set();\n\nfor (const user of botUsers) {\n const phone = normalisePhone(user.phone);\n if (!phone) {\n report.summary.users_without_phone++;\n continue;\n }\n report.summary.users_with_phone++;\n\n const deal = dealByPhone[phone];\n const person = personByPhone[phone];\n const issues = [];\n\n if (!deal) {\n report.summary.deal_missing++;\n report.missing_deals.push({\n bot_user_id: user.id,\n name: (user.first_name || '') + ' ' + (user.last_name || ''),\n phone: user.phone,\n lesson: user.current_lesson_number,\n completed: user.is_completed,\n });\n continue;\n }\n\n matchedPhones.add(phone);\n report.summary.deal_found++;\n\n // Check stage\n const exp = expectedStage(user);\n const actualStageGuid = deal.PipelineStageId || '';\n const actualStageName = stageToName[actualStageGuid] || actualStageGuid;\n\n if (actualStageGuid === exp.guid) {\n report.summary.stage_match++;\n } else {\n report.summary.stage_mismatch++;\n report.stage_mismatches.push({\n bot_user_id: user.id,\n name: (user.first_name || '') + ' ' + (user.last_name || ''),\n phone: user.phone,\n expected_stage: exp.name,\n actual_stage: actualStageName,\n deal_id: deal.Id,\n lesson: user.current_lesson_number,\n completed: user.is_completed,\n });\n issues.push('stage_mismatch');\n }\n\n // Check deal status\n const expectedStatus = user.is_completed ? 'Won' : 'Pending';\n const actualStatus = deal.Status || 'Unknown';\n if (actualStatus === expectedStatus) {\n report.summary.status_match++;\n } else {\n report.summary.status_mismatch++;\n report.status_mismatches.push({\n bot_user_id: user.id,\n name: (user.first_name || '') + ' ' + (user.last_name || ''),\n phone: user.phone,\n expected_status: expectedStatus,\n actual_status: actualStatus,\n deal_id: deal.Id,\n });\n issues.push('status_mismatch');\n }\n\n // Check lead_score (on embedded Person custom fields)\n const crmLeadScoreField = CONFIG.CUSTOM_FIELDS?.lead_score;\n if (crmLeadScoreField && crmLeadScoreField !== 'FIELD_GUID' && person?.Fields) {\n const crmScore = parseInt(person.Fields[crmLeadScoreField] || '0', 10);\n const botScore = user.lead_score || 0;\n if (crmScore === botScore) {\n report.summary.lead_score_match++;\n } else {\n report.summary.lead_score_mismatch++;\n report.lead_score_mismatches.push({\n bot_user_id: user.id,\n name: (user.first_name || '') + ' ' + (user.last_name || ''),\n phone: user.phone,\n bot_lead_score: botScore,\n crm_lead_score: crmScore,\n crm_person_id: person.Id,\n });\n issues.push('lead_score_mismatch');\n }\n }\n\n if (issues.length === 0) {\n report.summary.fully_synced++;\n }\n}\n\n// Find orphan deals (in pipeline but no matching bot user)\nconst botPhones = new Set(botUsers.map(u => normalisePhone(u.phone)).filter(Boolean));\nfor (const deal of deals) {\n const person = deal.Person || deal.Contact || {};\n const phones = [person.MobilePhone, person.WorkPhone].filter(Boolean).map(normalisePhone);\n const hasMatch = phones.some(ph => botPhones.has(ph));\n if (!hasMatch) {\n report.orphan_deals.push({\n deal_id: deal.Id,\n deal_title: deal.Title || '',\n person_name: person.DisplayName || 'Unknown',\n phone: person.MobilePhone || '',\n stage: stageToName[deal.PipelineStageId] || deal.PipelineStageId,\n status: deal.Status,\n });\n }\n}\n\nreturn [{json: report}];\n",
"mode": "runOnceForAllItems"
}
},
{
"id": "format_report",
"name": "Format Report",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [
2350,
500
],
"parameters": {
"jsCode": "\nconst r = $input.first().json;\nconst s = r.summary;\n\nconst lines = [];\nlines.push('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');\nlines.push(' \ud83d\udcca \u06af\u0632\u0627\u0631\u0634 \u0622\u062f\u06cc\u062a \u0631\u0628\u0627\u062a \u2194 CRM \u062f\u06cc\u062f\u0627\u0631');\nlines.push(' CRM Sync Audit Report');\nlines.push('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');\nlines.push('');\nlines.push('\ud83d\udccb \u062e\u0644\u0627\u0635\u0647 / Summary');\nlines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\nlines.push(` \u06a9\u0627\u0631\u0628\u0631\u0627\u0646 \u0631\u0628\u0627\u062a (\u06a9\u0644) : ${s.total_bot_users}`);\nlines.push(` \u062f\u0627\u0631\u0627\u06cc \u0634\u0645\u0627\u0631\u0647 \u062a\u0644\u0641\u0646 : ${s.users_with_phone}`);\nlines.push(` \u0628\u062f\u0648\u0646 \u0634\u0645\u0627\u0631\u0647 \u062a\u0644\u0641\u0646 : ${s.users_without_phone}`);\nlines.push(` \u062f\u06cc\u0644\u200c\u0647\u0627\u06cc CRM : ${s.total_crm_deals}`);\nlines.push('');\nlines.push('\ud83d\udd0d \u0646\u062a\u0627\u06cc\u062c \u0645\u0642\u0627\u06cc\u0633\u0647 / Comparison Results');\nlines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\nlines.push(` \u2705 \u062f\u06cc\u0644 \u067e\u06cc\u062f\u0627 \u0634\u062f : ${s.deal_found}`);\nlines.push(` \u274c \u062f\u06cc\u0644 \u0646\u0627\u0645\u0648\u062c\u0648\u062f : ${s.deal_missing}`);\nlines.push(` \u2705 \u0627\u0633\u062a\u06cc\u062c \u0635\u062d\u06cc\u062d : ${s.stage_match}`);\nlines.push(` \u274c \u0627\u0633\u062a\u06cc\u062c \u0627\u0634\u062a\u0628\u0627\u0647 : ${s.stage_mismatch}`);\nlines.push(` \u2705 \u0648\u0636\u0639\u06cc\u062a \u0635\u062d\u06cc\u062d : ${s.status_match}`);\nlines.push(` \u274c \u0648\u0636\u0639\u06cc\u062a \u0627\u0634\u062a\u0628\u0627\u0647 : ${s.status_mismatch}`);\nlines.push(` \u2705 \u0627\u0645\u062a\u06cc\u0627\u0632 \u0644\u06cc\u062f \u0635\u062d\u06cc\u062d : ${s.lead_score_match}`);\nlines.push(` \u274c \u0627\u0645\u062a\u06cc\u0627\u0632 \u0644\u06cc\u062f \u0627\u0634\u062a\u0628\u0627\u0647 : ${s.lead_score_mismatch}`);\nlines.push('');\n\nconst syncRate = s.users_with_phone > 0\n ? ((s.fully_synced / s.users_with_phone) * 100).toFixed(1)\n : '0.0';\nlines.push(` \ud83c\udfaf \u06a9\u0627\u0645\u0644\u0627\u064b \u0633\u06cc\u0646\u06a9 \u0634\u062f\u0647: ${s.fully_synced} / ${s.users_with_phone} (${syncRate}%)`);\nlines.push('');\n\n// \u2500\u2500 Details sections \u2500\u2500\nif (r.missing_deals.length > 0) {\n lines.push('');\n lines.push('\ud83d\udeab \u062f\u06cc\u0644 \u0646\u0627\u0645\u0648\u062c\u0648\u062f \u062f\u0631 CRM / Missing Deals');\n lines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\n for (const d of r.missing_deals.slice(0, 50)) {\n lines.push(` \u2022 ${d.name} | \ud83d\udcf1 ${d.phone} | \u062f\u0631\u0633 ${d.lesson || '-'} | ${d.completed ? '\u062a\u06a9\u0645\u06cc\u0644' : '\u0641\u0639\u0627\u0644'}`);\n }\n if (r.missing_deals.length > 50) {\n lines.push(` ... \u0648 ${r.missing_deals.length - 50} \u0645\u0648\u0631\u062f \u062f\u06cc\u06af\u0631`);\n }\n}\n\nif (r.stage_mismatches.length > 0) {\n lines.push('');\n lines.push('\u26a0\ufe0f \u0639\u062f\u0645 \u062a\u0637\u0627\u0628\u0642 \u0627\u0633\u062a\u06cc\u062c / Stage Mismatches');\n lines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\n for (const m of r.stage_mismatches.slice(0, 50)) {\n lines.push(` \u2022 ${m.name} | \ud83d\udcf1 ${m.phone} | \u0645\u0648\u0631\u062f \u0627\u0646\u062a\u0638\u0627\u0631: ${m.expected_stage} | \u0648\u0627\u0642\u0639\u06cc: ${m.actual_stage}`);\n }\n if (r.stage_mismatches.length > 50) {\n lines.push(` ... \u0648 ${r.stage_mismatches.length - 50} \u0645\u0648\u0631\u062f \u062f\u06cc\u06af\u0631`);\n }\n}\n\nif (r.status_mismatches.length > 0) {\n lines.push('');\n lines.push('\u26a0\ufe0f \u0639\u062f\u0645 \u062a\u0637\u0627\u0628\u0642 \u0648\u0636\u0639\u06cc\u062a \u062f\u06cc\u0644 / Status Mismatches');\n lines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\n for (const m of r.status_mismatches.slice(0, 50)) {\n lines.push(` \u2022 ${m.name} | \ud83d\udcf1 ${m.phone} | \u0645\u0648\u0631\u062f \u0627\u0646\u062a\u0638\u0627\u0631: ${m.expected_status} | \u0648\u0627\u0642\u0639\u06cc: ${m.actual_status}`);\n }\n if (r.status_mismatches.length > 50) {\n lines.push(` ... \u0648 ${r.status_mismatches.length - 50} \u0645\u0648\u0631\u062f \u062f\u06cc\u06af\u0631`);\n }\n}\n\nif (r.lead_score_mismatches.length > 0) {\n lines.push('');\n lines.push('\u26a0\ufe0f \u0639\u062f\u0645 \u062a\u0637\u0627\u0628\u0642 \u0627\u0645\u062a\u06cc\u0627\u0632 \u0644\u06cc\u062f / Lead Score Mismatches');\n lines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\n for (const m of r.lead_score_mismatches.slice(0, 50)) {\n lines.push(` \u2022 ${m.name} | \ud83d\udcf1 ${m.phone} | \u0631\u0628\u0627\u062a: ${m.bot_lead_score} | CRM: ${m.crm_lead_score}`);\n }\n if (r.lead_score_mismatches.length > 50) {\n lines.push(` ... \u0648 ${r.lead_score_mismatches.length - 50} \u0645\u0648\u0631\u062f \u062f\u06cc\u06af\u0631`);\n }\n}\n\nif (r.orphan_deals.length > 0) {\n lines.push('');\n lines.push('\ud83d\udc7b \u062f\u06cc\u0644\u200c\u0647\u0627\u06cc \u06cc\u062a\u06cc\u0645 (\u0628\u062f\u0648\u0646 \u06a9\u0627\u0631\u0628\u0631 \u0631\u0628\u0627\u062a) / Orphan Deals');\n lines.push('\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');\n for (const d of r.orphan_deals.slice(0, 30)) {\n lines.push(` \u2022 ${d.person_name} | ${d.deal_title} | \u0627\u0633\u062a\u06cc\u062c: ${d.stage} | ${d.status}`);\n }\n if (r.orphan_deals.length > 30) {\n lines.push(` ... \u0648 ${r.orphan_deals.length - 30} \u0645\u0648\u0631\u062f \u062f\u06cc\u06af\u0631`);\n }\n}\n\nlines.push('');\nlines.push('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');\nlines.push(` \u062a\u0627\u0631\u06cc\u062e \u0627\u062c\u0631\u0627: ${new Date().toLocaleString('fa-IR', {timeZone: 'Asia/Tehran'})}`);\nlines.push('\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');\n\nconst reportText = lines.join('\\n');\n\nreturn [{json: {\n report_text: reportText,\n report_data: r,\n generated_at: new Date().toISOString(),\n}}];\n",
"mode": "runOnceForAllItems"
}
}
],
"connections": {
"Manual Trigger": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Config": {
"main": [
[
{
"node": "Login Bot Panel",
"type": "main",
"index": 0
}
]
]
},
"Login Bot Panel": {
"main": [
[
{
"node": "Extract Token",
"type": "main",
"index": 0
}
]
]
},
"Extract Token": {
"main": [
[
{
"node": "Fetch Bot Users",
"type": "main",
"index": 0
}
]
]
},
"Fetch Bot Users": {
"main": [
[
{
"node": "Extract Bot Users",
"type": "main",
"index": 0
}
]
]
},
"Extract Bot Users": {
"main": [
[
{
"node": "Fetch Didar Deals",
"type": "main",
"index": 0
}
]
]
},
"Fetch Didar Deals": {
"main": [
[
{
"node": "Compare & Audit",
"type": "main",
"index": 0
}
]
]
},
"Compare & Audit": {
"main": [
[
{
"node": "Format Report",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
{
"name": "course-bot"
},
{
"name": "audit"
},
{
"name": "didar-crm"
},
{
"name": "bale"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
CRM Audit — Bot vs Didar (Bale). Uses httpRequest. Event-driven trigger; 9 nodes.
Source: https://github.com/javid1371/telegram-course-bot/blob/85c7067292d185aafcb8ebe2f539e59cf032950c/n8n-workflows/crm-audit-bale.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.
Worflow. Uses whatsAppTrigger, httpRequest, whatsApp. Event-driven trigger; 94 nodes.
Webhook Slack. Uses theHiveProjectTrigger, stickyNote, httpRequest, theHiveProject. Event-driven trigger; 63 nodes.
Key Features: Direct Case Management: Modify case details such as assignee, severity, status, and more through intuitive form inputs embedded within Slack messages. Seamless Integration: Assumes match
N8N Complete Final. Uses telegramTrigger, dataTable, telegram, mqtt. Event-driven trigger; 58 nodes.
TextMain. Uses telegramTrigger, stopAndError, telegram, httpRequest. Event-driven trigger; 56 nodes.