AutomationFlowsMarketing & Ads › Automated Whatsapp Lead Nurturing with Personalized Messages via Postgres &…

Automated Whatsapp Lead Nurturing with Personalized Messages via Postgres &…

Original n8n title: Automated Whatsapp Lead Nurturing with Personalized Messages via Postgres & Gallabox

ByRahi Uppal @rahiuppal on n8n.io

This workflow fetches unqualified leads from Postgres at defined retry intervals, sends personalized WhatsApp template messages via Gallabox API, and logs message activity while updating lead status in the database. Schedule Trigger Type: Runs the workflow automatically at set…

Cron / scheduled trigger★★★★☆ complexity11 nodesPostgresHTTP Request
Marketing & Ads Trigger: Cron / scheduled Nodes: 11 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #7712 — we link there as the canonical source.

This workflow follows the HTTP Request → Postgres recipe pattern — see all workflows that pair these two integrations.

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 →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "84e5aa63-1375-4aa5-980a-b8d252d7535b",
      "name": "Execute a SQL query",
      "type": "n8n-nodes-base.postgres",
      "onError": "continueRegularOutput",
      "position": [
        4040,
        520
      ],
      "parameters": {
        "query": "SELECT * FROM \"MQL\".mql_contacts\nWHERE (\n  (count = 0)\n   OR \n  (count = 1 AND (NOW() AT TIME ZONE 'Asia/Kolkata') - webhook_time > INTERVAL '3 minutes')\n   OR \n  (count = 2 AND (NOW() AT TIME ZONE 'Asia/Kolkata') - webhook_time > INTERVAL '5 minutes')\n   OR \n  (count = 3 AND (NOW() AT TIME ZONE 'Asia/Kolkata') - webhook_time > INTERVAL '8 minutes')\n)\n  AND\n  disposition = 'unqualified'\n  ;",
        "options": {},
        "operation": "executeQuery"
      },
      "retryOnFail": true,
      "typeVersion": 2.6,
      "alwaysOutputData": true
    },
    {
      "id": "4c385ae2-6ffe-4f84-8647-cc347dd32ad4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4000,
        680
      ],
      "parameters": {
        "width": 176,
        "height": 80,
        "content": "Gets unqualified leads which count 0,1,2,3 respective time"
      },
      "typeVersion": 1
    },
    {
      "id": "fcdf84ff-57e4-4faa-adcb-c0e3d707e34c",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        3720,
        520
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "seconds"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "00e9e762-8a4a-46be-85e8-e3bbd86bfc07",
      "name": "Code1",
      "type": "n8n-nodes-base.code",
      "position": [
        4780,
        540
      ],
      "parameters": {
        "jsCode": "// Define matrix with count mapping\nconst matrix = {\n  nexus: {\n    0: \"\ud83d\udef5 sample1\",\n    1: \"\u26a1\ufe0f sample1\",\n    2: \"\ud83d\udd0b sample1\",\n    3: \"\u2728 sample1\"\n  },\n  magnus: {\n    0: \"\ud83d\udef5 sample2\",\n    1: \"\u26a1\ufe0f sample2\",\n    2: \"\ud83d\udd0b sample2\",\n    3: \"\u2728 sample2\"\n  },\n  reo: {\n    0: \"\ud83d\udef5 sample3\",\n    1: \"\u26a1\ufe0f sample3\",\n    2: \"\ud83d\udd0b sample3\",\n    3: \"\u2728sample3\"\n  },\n  general: {\n    0: \"\ud83d\udef5 sample4\",\n    1: \"\u26a1\ufe0fsample4\",\n    2: \"\ud83d\udd0b sample4\",\n    3: \"\u2728 sample3\"\n  }\n};\n\n// Get inputs from previous node\nconst model = $input.first().json.model// \"nexus\" / \"reo\" / \"magnus\" / \"general\"\nconst count =  $input.first().json.count // 0 / 1 / 2 / 3\n\n// const model = \"general\"; \n// const count = 0; \n\n// Fetch matching content\nconst output = matrix[model]?.[count] || \"\ud83d\udef5 default\";\n\n// Return as output\nreturn [{ json: { model, count, output } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "8c5fad3d-46b3-427e-ab5a-205712394bd0",
      "name": "Loop Over Items4",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        4520,
        520
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "a7846d82-40fa-4f73-b22a-a100009d276c",
      "name": "new_lead_4",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        5000,
        540
      ],
      "parameters": {
        "url": "https://server.gallabox.com/devapi/messages/whatsapp",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        },
        "jsonBody": "=add here your copy api for whatsapp sending\n{\n    \"channelId\": \"0\",\n    \"channelType\": \"whatsapp\",\n    \"recipient\": {\n        \"name\": \"{{ $('Execute a SQL query').item.json.name }}\",\n        \"phone\": \"91{{ $('Execute a SQL query').item.json.phone }}\"\n    },\n    \"whatsapp\": {\n        \"type\": \"template\",\n        \"template\": {\n            \"templateName\": \"waba_qual_21july25\",\n            \"bodyValues\": {\n                \"Name\": \"{{ $('Execute a SQL query').item.json.name }}\",\n                \"Details\": \"{{ $json.output }}\"\n            },\n            \"buttonValues\": [\n                {\n                    \"index\": 0,\n                    \"sub_type\": \"quick_reply\",\n                    \"parameters\": {\n                        \"type\": \"payload\",\n                        \"payload\": \"Show Brochure\"\n                    }\n                },\n                {\n                    \"index\": 1,\n                    \"sub_type\": \"quick_reply\",\n                    \"parameters\": {\n                        \"type\": \"payload\",\n                        \"payload\": \"Get Showroom Location\"\n                    }\n                },\n                {\n                    \"index\": 2,\n                    \"sub_type\": \"quick_reply\",\n                    \"parameters\": {\n                        \"type\": \"payload\",\n                        \"payload\": \"Not Interested\"\n                    }\n                }\n            ]\n        }\n    }\n}",
        "sendBody": true,
        "jsonHeaders": "{\n  \"apiKey\": \"\",\n  \"apiSecret\": \"\"\n}",
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "specifyHeaders": "json",
        "genericAuthType": "httpCustomAuth"
      },
      "typeVersion": 4.1
    },
    {
      "id": "505800b6-fbe6-49bd-bd97-5cfb3a34da8c",
      "name": "Update rows in a table4",
      "type": "n8n-nodes-base.postgres",
      "position": [
        5500,
        540
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "mql_contacts",
          "cachedResultName": "mql_contacts"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "MQL",
          "cachedResultName": "MQL"
        },
        "columns": {
          "value": {
            "count": "={{ $('Execute a SQL query').item.json.count + 1  }}",
            "phone": "={{ $('Execute a SQL query').item.json.phone }}",
            "pincode": 0,
            "last_message_sent": "={{ $json.last_sent }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "type": "dateTime",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "updated_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "number",
              "display": true,
              "removed": false,
              "required": true,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_message_sent",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "last_message_sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "disposition",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "disposition",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "count",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "interval",
              "type": "number",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "interval",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "remarks",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "remarks",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "model",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "model",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "pincode",
              "type": "number",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "pincode",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ABOS API status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "ABOS API status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "webhook_time",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "webhook_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "phone"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "typeVersion": 2.6
    },
    {
      "id": "f7729e9d-8f3b-477a-88fe-513be43997e4",
      "name": "Insert rows in a table4",
      "type": "n8n-nodes-base.postgres",
      "position": [
        5280,
        540
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "mql_logs",
          "cachedResultName": "mql_logs"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "MQL",
          "cachedResultName": "MQL"
        },
        "columns": {
          "value": {
            "name": "={{ $('Execute a SQL query').item.json.name }}",
            "phone": "={{ $('Execute a SQL query').item.json.phone }}",
            "remarks": "Workflow 1",
            "last_sent": "={{ $('Execute a SQL query').item.json.last_message_sent }}",
            "mes_count": "={{ $('Execute a SQL query').item.json.count }}",
            "message_id": "={{ $json.body.id }}",
            "disposition": "={{ $('Execute a SQL query').item.json.disposition }}",
            "gb_status_code": "={{ $json.statusCode }}",
            "gb_status_message": "={{ $json.body.status }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "created_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "updated_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "message_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "message_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "number",
              "display": true,
              "required": true,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "disposition",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "disposition",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "mes_count",
              "type": "number",
              "display": true,
              "required": false,
              "displayName": "mes_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_sent",
              "type": "dateTime",
              "display": true,
              "required": false,
              "displayName": "last_sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "gb_status_code",
              "type": "number",
              "display": true,
              "required": false,
              "displayName": "gb_status_code",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "gb_status_message",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "gb_status_message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "message_status_meta",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "message_status_meta",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "cta",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "cta",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "remarks",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "remarks",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "typeVersion": 2.6
    },
    {
      "id": "a6bb388a-17f3-4e24-94a4-47abf67dacf4",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4640,
        420
      ],
      "parameters": {
        "width": 216,
        "height": 80,
        "content": "Matrixed code to add unque message for pushing that to message with variable\n"
      },
      "typeVersion": 1
    },
    {
      "id": "afd6a70f-80ae-4c3e-8b82-bd784dacfbe5",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5000,
        420
      ],
      "parameters": {
        "width": 150,
        "height": 80,
        "content": "Gallabox/whatsapp sending api"
      },
      "typeVersion": 1
    },
    {
      "id": "13fe2f75-fe06-423a-9334-a4be0025624d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5380,
        420
      ],
      "parameters": {
        "width": 150,
        "height": 80,
        "content": "Postgres connection to store data "
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Code1": {
      "main": [
        [
          {
            "node": "new_lead_4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "new_lead_4": {
      "main": [
        [
          {
            "node": "Insert rows in a table4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items4": {
      "main": [
        [],
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute a SQL query": {
      "main": [
        [
          {
            "node": "Loop Over Items4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert rows in a table4": {
      "main": [
        [
          {
            "node": "Update rows in a table4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update rows in a table4": {
      "main": [
        [
          {
            "node": "Loop Over Items4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow fetches unqualified leads from Postgres at defined retry intervals, sends personalized WhatsApp template messages via Gallabox API, and logs message activity while updating lead status in the database. Schedule Trigger Type: Runs the workflow automatically at set…

Source: https://n8n.io/workflows/7712/ — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Marketing & Ads

Workflow A — WhatsApp Lead Intake & Qualification. Uses postgres, httpRequest, errorTrigger. Scheduled trigger; 67 nodes.

Postgres, HTTP Request, Error Trigger
Marketing & Ads

Build authentic Reddit presence and generate qualified leads through AI-powered community engagement that provides genuine value without spam or promotion.

HTTP Request, Reddit
Marketing & Ads

This workflow automates bulk email campaigns with built-in validation, deliverability protection, and smart send-time optimization.

HTTP Request, Postgres, Gmail
Marketing & Ads

This workflow runs on scheduled weekly and monthly triggers to generate unified marketing performance reports. It processes multiple websites by collecting analytics data, paid ads performance, and CR

Gmail, Google Sheets, Google Analytics +3
Marketing & Ads

Fetch Multiple Google Analytics GA4 metrics daily, post to Discord, update previous day’s entry as GA data finalizes over seven days. Automates daily traffic reporting Maintains single message per day

Google Analytics, Discord, HTTP Request