{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "12d90162-611c-4dfb-9df6-f2d1c5678dc5",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        1408,
        288
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    },
    {
      "id": "77c0b0c8-a5b7-4c64-9c18-841d441455f7",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        1184,
        288
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "97efda03-34e8-4360-a517-f445d720fb3c",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.Phone_Format_Valid }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c1a6bc2e-a88e-4bfc-a544-c46ed92e0308",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        48,
        272
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f9fe2082-1288-412b-916e-555f5c4ac766",
      "name": "process one by one",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        496,
        272
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "605d1dd8-10bf-497b-b351-36dff76affe7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -576,
        144
      ],
      "parameters": {
        "width": 544,
        "height": 560,
        "content": "## WhatsApp number checker\nThis flow is meant to act as a WhatsApp number checker for a spreadsheet list. It is useful when you have a list of leads or contacts and want to prequalify which phone numbers appear to be registered on WhatsApp before doing messaging or follow-up.\n\n## Use as it is or integrate it as a module in a more complex workflow\n\n## Requirements\n- Google Sheets access\n- WasenderAPI subscription and `n8n\u2011nodes\u2011wasenderapi` installed\n\n## How to set up\n- Duplicate the sample Google Sheet and fill in your phone numbers under `Mobile Number`.\n***template sheet***\nhttps://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit?usp=sharing\n- Install the **`n8n\u2011nodes\u2011wasenderapi`** community nodes.\n- Configure your Google Sheets OAuth2 and WasenderAPI credentials.\n- Adjust the `Wait` node delay if needed to avoid rate limits (currently set to 10 sec.).\n- Set your WhatsApp session and the target number for notifications"
      },
      "typeVersion": 1
    },
    {
      "id": "997ebd53-e3d9-43ce-bc22-523f48b5ee8e",
      "name": "Load phone numbers from Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        272,
        272
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit#gid=0",
          "cachedResultName": "Phone#"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit?usp=drivesdk",
          "cachedResultName": "WhatsApp # checker (template - save a copy)"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "6563fc9e-9bca-4534-9613-270ffb73f179",
      "name": "Normalize phone number",
      "type": "n8n-nodes-base.code",
      "position": [
        736,
        288
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nreturn items.map(item => {\n  const raw = item.json['Mobile Number'];\n  const clean = String(raw).replace(/[^\\d]/g, ''); // keeps only digits\n\n  return {\n    json: {\n      ...item.json,\n      // Optional: keep original visible\n      Mobile_Number_Original: raw,\n      // What you want to send to Wasender\n      Mobile_Number_E164: clean,\n    },\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "f149218e-0639-4081-8807-7ffcc8e11737",
      "name": "Validate international phone format",
      "type": "n8n-nodes-base.code",
      "position": [
        960,
        288
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nconst countryMap = {\n  '1':   { country: 'US/CA', nsnLengths: [10] },\n  '20':  { country: 'Egypt', nsnLengths: [10] },\n  '27':  { country: 'South Africa', nsnLengths: [9] },\n  '30':  { country: 'Greece', nsnLengths: [10] },\n  '31':  { country: 'Netherlands', nsnLengths: [9] },\n  '32':  { country: 'Belgium', nsnLengths: [8, 9] },\n  '33':  { country: 'France', nsnLengths: [9] },\n  '34':  { country: 'Spain', nsnLengths: [9] },\n  '36':  { country: 'Hungary', nsnLengths: [8, 9] },\n  '39':  { country: 'Italy', nsnLengths: [8, 9, 10] },\n  '40':  { country: 'Romania', nsnLengths: [9] },\n  '41':  { country: 'Switzerland', nsnLengths: [9] },\n  '43':  { country: 'Austria', nsnLengths: [10, 11, 12] },\n  '44':  { country: 'United Kingdom', nsnLengths: [9, 10] },\n  '45':  { country: 'Denmark', nsnLengths: [8] },\n  '46':  { country: 'Sweden', nsnLengths: [7, 8, 9] },\n  '47':  { country: 'Norway', nsnLengths: [8] },\n  '48':  { country: 'Poland', nsnLengths: [9] },\n  '49':  { country: 'Germany', nsnLengths: [10, 11] },\n  '52':  { country: 'Mexico', nsnLengths: [10] },\n  '55':  { country: 'Brazil', nsnLengths: [10, 11] },\n  '61':  { country: 'Australia', nsnLengths: [9] },\n  '64':  { country: 'New Zealand', nsnLengths: [8, 9, 10] },\n  '81':  { country: 'Japan', nsnLengths: [9, 10] },\n  '82':  { country: 'South Korea', nsnLengths: [9, 10] },\n  '86':  { country: 'China', nsnLengths: [11] },\n  '90':  { country: 'Turkey', nsnLengths: [10] },\n  '91':  { country: 'India', nsnLengths: [10] },\n  '212': { country: 'Morocco', nsnLengths: [9] },\n  '213': { country: 'Algeria', nsnLengths: [8, 9] },\n  '216': { country: 'Tunisia', nsnLengths: [8] },\n  '230': { country: 'Mauritius', nsnLengths: [7, 8] },\n  '234': { country: 'Nigeria', nsnLengths: [10] },\n  '351': { country: 'Portugal', nsnLengths: [9] },\n  '352': { country: 'Luxembourg', nsnLengths: [8, 9] },\n  '353': { country: 'Ireland', nsnLengths: [9] },\n  '354': { country: 'Iceland', nsnLengths: [7, 8, 9] },\n  '355': { country: 'Albania', nsnLengths: [8, 9] },\n  '356': { country: 'Malta', nsnLengths: [8] },\n  '357': { country: 'Cyprus', nsnLengths: [8] },\n  '358': { country: 'Finland', nsnLengths: [7, 8, 9, 10] },\n  '359': { country: 'Bulgaria', nsnLengths: [8, 9] },\n  '373': { country: 'Moldova', nsnLengths: [8] },\n  '380': { country: 'Ukraine', nsnLengths: [9] },\n  '381': { country: 'Serbia', nsnLengths: [8, 9] },\n  '385': { country: 'Croatia', nsnLengths: [8, 9] },\n  '386': { country: 'Slovenia', nsnLengths: [8] },\n  '387': { country: 'Bosnia and Herzegovina', nsnLengths: [8] },\n  '389': { country: 'North Macedonia', nsnLengths: [8] },\n  '420': { country: 'Czech Republic', nsnLengths: [9] },\n  '421': { country: 'Slovakia', nsnLengths: [9] },\n  '971': { country: 'United Arab Emirates', nsnLengths: [8, 9] },\n  '972': { country: 'Israel', nsnLengths: [8, 9] },\n  '974': { country: 'Qatar', nsnLengths: [8] }\n};\n\nfunction detectCountryCode(number) {\n  for (const len of [3, 2, 1]) {\n    const code = number.slice(0, len);\n    if (countryMap[code]) {\n      return {\n        countryCode: code,\n        country: countryMap[code].country,\n        nsnLengths: countryMap[code].nsnLengths\n      };\n    }\n  }\n\n  return {\n    countryCode: null,\n    country: 'Unknown',\n    nsnLengths: []\n  };\n}\n\nfunction validateNumber(number, detected) {\n  if (!number || !/^\\d+$/.test(number)) {\n    return {\n      valid: false,\n      reason: 'Number must contain digits only'\n    };\n  }\n\n  if (number.length < 8 || number.length > 15) {\n    return {\n      valid: false,\n      reason: 'Total length must be between 8 and 15 digits'\n    };\n  }\n\n  if (!detected.countryCode) {\n    return {\n      valid: false,\n      reason: 'Unknown country code'\n    };\n  }\n\n  const nationalNumber = number.slice(detected.countryCode.length);\n\n  if (!detected.nsnLengths.includes(nationalNumber.length)) {\n    return {\n      valid: false,\n      reason: `Invalid length for ${detected.country}. Expected national number length: ${detected.nsnLengths.join(', ')}`\n    };\n  }\n\n  return {\n    valid: true,\n    reason: 'Valid format'\n  };\n}\n\nreturn items.map(item => {\n  const raw = item.json.Mobile_Number_E164 || '';\n  const number = String(raw).replace(/\\D/g, '');\n\n  const detected = detectCountryCode(number);\n  const validation = validateNumber(number, detected);\n\n  return {\n    json: {\n      ...item.json,\n      Mobile_Number_Checked: number,\n      Country_Code: detected.countryCode,\n      Country: detected.country,\n      National_Number: detected.countryCode ? number.slice(detected.countryCode.length) : null,\n      Phone_Format_Valid: validation.valid,\n      Phone_Format_Reason: validation.reason\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "63066c4f-3ba3-44ed-83df-70bcecffdda3",
      "name": "Check WhatsApp registration with WasenderAPI",
      "type": "n8n-nodes-wasenderapi.wasenderApi",
      "onError": "continueErrorOutput",
      "position": [
        1632,
        288
      ],
      "parameters": {
        "resource": "contact",
        "operation": "checkOnWhatsApp",
        "sessionId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "phoneOrJid": "={{ $json.Mobile_Number_E164 }}",
        "requestOptions": {
          "maxRetries": 1,
          "retryOnFail": false
        }
      },
      "credentials": {
        "wasenderAccountApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "84a0838f-df5d-4bc4-a00e-90838c52d130",
      "name": "Update result in Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1840,
        400
      ],
      "parameters": {
        "columns": {
          "value": {
            "1": "={{ $('Load phone numbers from Google Sheets').item.json['1'] }}",
            "Check": "={{ $json.exists !== undefined ? ($json.exists ? 'Yes' : 'No') : 'Error' }}"
          },
          "schema": [
            {
              "id": "1",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "1",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Mobile Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Mobile Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Check",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Check",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "1"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit#gid=0",
          "cachedResultName": "Phone#"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit?usp=drivesdk",
          "cachedResultName": "WhatsApp # checker (template - save a copy)"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "100d7ad0-f671-4ae5-ad00-cfe8483930cf",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        208
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 352,
        "content": "## normalize and validate phone numbers\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f03eab14-7aa4-44c8-b61d-3024f8c7f5d6",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        208
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 352,
        "content": "## check WhatsApp, write result back\n"
      },
      "typeVersion": 1
    },
    {
      "id": "29c2aa7f-d08f-41b4-8b3f-42b32acd5bb0",
      "name": "Notify error",
      "type": "n8n-nodes-wasenderapi.wasenderApi",
      "position": [
        1840,
        640
      ],
      "parameters": {
        "to": "<your phone number>",
        "text": "Check the phone# on line {{ $('Load phone numbers from Google Sheets').item.json['1'] }}, there is an error. the verification continues for the list",
        "sessionId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "messageOptions": {},
        "requestOptions": {
          "maxRetries": 10,
          "retryOnFail": true
        }
      },
      "credentials": {
        "wasenderAccountApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "57be28de-c81a-4053-9b21-2ada004c66e6",
      "name": "Notify check complete",
      "type": "n8n-nodes-wasenderapi.wasenderApi",
      "position": [
        720,
        64
      ],
      "parameters": {
        "to": "<your phone number>",
        "text": "The last verification is now complete.",
        "sessionId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "messageOptions": {},
        "requestOptions": {
          "maxRetries": 10,
          "retryOnFail": true
        }
      },
      "credentials": {
        "wasenderAccountApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e47c0c78-a2ac-4872-ac93-c978e8df3390",
      "name": "write Invalid format",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1200,
        608
      ],
      "parameters": {
        "columns": {
          "value": {
            "1": "={{ $('Load phone numbers from Google Sheets').item.json['1'] }}",
            "Check": "=Invalid format"
          },
          "schema": [
            {
              "id": "1",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "1",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Mobile Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Mobile Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Check",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Check",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "1"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit#gid=0",
          "cachedResultName": "Phone#"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1K0ps-y9OVJ5L15dnOekIxxTwxvTa0zOQNwGDEFSrYYY/edit?usp=drivesdk",
          "cachedResultName": "WhatsApp # checker (template - save a copy)"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    }
  ],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "write Invalid format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Check WhatsApp registration with WasenderAPI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "process one by one": {
      "main": [
        [
          {
            "node": "Notify check complete",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Normalize phone number",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "write Invalid format": {
      "main": [
        [
          {
            "node": "process one by one",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize phone number": {
      "main": [
        [
          {
            "node": "Validate international phone format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update result in Google Sheets": {
      "main": [
        [
          {
            "node": "process one by one",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate international phone format": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Load phone numbers from Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load phone numbers from Google Sheets": {
      "main": [
        [
          {
            "node": "process one by one",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check WhatsApp registration with WasenderAPI": {
      "main": [
        [
          {
            "node": "Update result in Google Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}