AutomationFlowsData & Sheets › Clinic Missed Call Wa Recovery

Clinic Missed Call Wa Recovery

20 - Clinic Missed Call WA Recovery. Uses googleSheets, httpRequest, twilio. Webhook trigger; 8 nodes.

Webhook trigger★★★★☆ complexity8 nodesGoogle SheetsHTTP RequestTwilio
Data & Sheets Trigger: Webhook Nodes: 8 Complexity: ★★★★☆ Added:

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

This workflow follows the Google Sheets → HTTP Request 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
{
  "name": "20 - Clinic Missed Call WA Recovery",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "twilio-missed-call",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "webhook-call",
      "name": "Twilio status webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        200,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.body.CallStatus }}",
              "rightValue": "no-answer",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "leftValue": "={{ $json.body.Direction }}",
              "rightValue": "inbound",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "or"
        }
      },
      "id": "if-missed",
      "name": "If missed inbound",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        420,
        300
      ]
    },
    {
      "parameters": {
        "operation": "lookup",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_ME_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "patients_db",
          "mode": "name"
        },
        "lookupColumn": "phone",
        "lookupValue": "={{ $('Twilio status webhook').first().json.body.From }}",
        "options": {}
      },
      "id": "patient-lookup",
      "name": "Lookup patient",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        640,
        300
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "=https://api.cal.com/v1/availability",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "eventTypeId",
              "value": "REPLACE_ME_CALCOM_EVENT_ID"
            },
            {
              "name": "dateFrom",
              "value": "={{ $now.toISO() }}"
            },
            {
              "name": "dateTo",
              "value": "={{ $now.plus({days: 3}).toISO() }}"
            }
          ]
        },
        "options": {}
      },
      "id": "fetch-slots",
      "name": "Fetch Cal.com slots",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        860,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const slots = $input.first().json.busy ? [] : ($input.first().json.availabilities || []);\nconst now = new Date();\nconst nextTwo = slots.filter(s => new Date(s.start) > now).slice(0, 2);\nconst formatSlot = (s) => {\n  const d = new Date(s.start);\n  return d.toLocaleString('en-US', {weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit'});\n};\nconst patient = $('Lookup patient').first().json;\nconst from = $('Twilio status webhook').first().json.body.From;\nreturn [{\n  json: {\n    patient_name: patient.full_name || 'there',\n    patient_phone: from,\n    is_returning: !!patient.last_visit_at,\n    slot_1: nextTwo[0] ? formatSlot(nextTwo[0]) : 'tomorrow 10:00 AM',\n    slot_2: nextTwo[1] ? formatSlot(nextTwo[1]) : 'tomorrow 2:00 PM',\n    booking_link: `https://cal.com/REPLACE_ME_CALCOM_USER/REPLACE_ME_EVENT_SLUG?phone=${encodeURIComponent(from)}`\n  }\n}];"
      },
      "id": "compose",
      "name": "Compose WA params",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1080,
        300
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "send",
        "from": "whatsapp:REPLACE_ME_TWILIO_FROM",
        "to": "=whatsapp:{{ $json.patient_phone }}",
        "toWhatsapp": true,
        "message": "=Hi {{ $json.patient_name }}, sorry we missed your call to the clinic. Two slots open in the next 3 days: {{ $json.slot_1 }} or {{ $json.slot_2 }}. Book direct here: {{ $json.booking_link }}. If urgent, reply URGENT and the front desk will call back within 30 min.",
        "options": {
          "contentSid": "REPLACE_ME_WA_TEMPLATE_SID"
        }
      },
      "id": "twilio-wa",
      "name": "Send WA recovery",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1300,
        300
      ],
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://services.leadconnectorhq.com/contacts/upsert",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"locationId\": \"REPLACE_ME_GHL_LOCATION\",\n  \"phone\": \"{{ $('Compose WA params').first().json.patient_phone }}\",\n  \"firstName\": \"{{ $('Compose WA params').first().json.patient_name }}\",\n  \"tags\": [\"missed-call-recovered\", \"wa-followup-sent\"],\n  \"source\": \"clinic-missed-call-bot\"\n}",
        "options": {}
      },
      "id": "ghl-upsert",
      "name": "Upsert to GHL CRM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1520,
        300
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_ME_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "missed_call_log",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "ts": "={{ $now.toISO() }}",
            "from_phone": "={{ $('Compose WA params').first().json.patient_phone }}",
            "patient_name": "={{ $('Compose WA params').first().json.patient_name }}",
            "is_returning": "={{ $('Compose WA params').first().json.is_returning }}",
            "slot_1_offered": "={{ $('Compose WA params').first().json.slot_1 }}",
            "slot_2_offered": "={{ $('Compose WA params').first().json.slot_2 }}",
            "wa_sid": "={{ $('Send WA recovery').first().json.sid }}",
            "status": "wa_sent"
          }
        },
        "options": {}
      },
      "id": "sheet-log",
      "name": "Log missed call",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1740,
        300
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Twilio status webhook": {
      "main": [
        [
          {
            "node": "If missed inbound",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If missed inbound": {
      "main": [
        [
          {
            "node": "Lookup patient",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Lookup patient": {
      "main": [
        [
          {
            "node": "Fetch Cal.com slots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Cal.com slots": {
      "main": [
        [
          {
            "node": "Compose WA params",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compose WA params": {
      "main": [
        [
          {
            "node": "Send WA recovery",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send WA recovery": {
      "main": [
        [
          {
            "node": "Upsert to GHL CRM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert to GHL CRM": {
      "main": [
        [
          {
            "node": "Log missed call",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateId": "skynetlabs-20"
  },
  "tags": [
    {
      "name": "skynetlabs-pack"
    },
    {
      "name": "healthcare"
    },
    {
      "name": "clinic-ops"
    },
    {
      "name": "whatsapp"
    }
  ]
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

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

About this workflow

20 - Clinic Missed Call WA Recovery. Uses googleSheets, httpRequest, twilio. Webhook trigger; 8 nodes.

Source: https://github.com/waseemnasir2k26/skynet-automation-pack/blob/main/n8n/20-clinic-missed-call-wa-recovery.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

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

Data & Sheets

Are you tired of manually entering open house visitor information into your CRM? Losing hot leads because you didn't follow up fast enough? This powerful n8n workflow automatically syncs every SignSna

Email Send, Google Sheets, HubSpot +3
Data & Sheets

16 - Abandoned Cart WA Voice Note. Uses httpRequest, awsS3, twilio, googleSheets. Webhook trigger; 9 nodes.

HTTP Request, AWS S3, Twilio +1
Data & Sheets

This template is ideal for solo store owners, eCommerce marketers, automation beginners, or anyone using Shopify and Gmail who wants to recover lost revenue without coding.

HTTP Request, Gmail, Twilio +3
Data & Sheets

[SANTOBET] FLUXO TODO - BACKUP. Uses googleSheets, httpRequest, googleSheetsTrigger. Webhook trigger; 57 nodes.

Google Sheets, HTTP Request, Google Sheets Trigger
Data & Sheets

FLUXO DISPARO DATA E HORA. Uses itemLists, googleSheets, httpRequest. Webhook trigger; 48 nodes.

Item Lists, Google Sheets, HTTP Request