AutomationFlowsSlack & Telegram › Recover Missed Clinic Appointments with Supabase and Whatsapp

Recover Missed Clinic Appointments with Supabase and Whatsapp

ByKanishka Shrivastava @kanishka-shrivastava on n8n.io

This workflow runs every 15 minutes to find unprocessed clinic appointments in Supabase that are more than 30 minutes past their scheduled time and sends a WhatsApp Business template message to the patient to prompt rebooking, then flags the appointment so it is not messaged…

Cron / scheduled trigger★★★★☆ complexity13 nodesSupabaseWhatsApp
Slack & Telegram Trigger: Cron / scheduled Nodes: 13 Complexity: ★★★★☆ Added:

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

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
{
  "id": "Jr3yG9uQ6tk0TLAV",
  "name": "Recover missed clinic appointments via WhatsApp",
  "tags": [],
  "nodes": [
    {
      "id": "73714a38-f42a-4299-9aef-2c9279e8b31f",
      "name": "Workflow overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 964,
        "content": "## Recover missed clinic appointments via WhatsApp\n\n## Who's it for\nClinics and small healthcare practices that lose revenue when patients miss appointments without notice. Replaces the manual no-show phone call with an automated WhatsApp nudge.\n\n## How it works\nEvery 15 minutes, this workflow checks Supabase for appointments past their scheduled time (plus a 30-minute grace period) with no check-in logged. For each no-show found, it sends the patient a pre-approved WhatsApp template letting them know they missed their appointment and inviting them to call or message back to rebook, then marks that appointment as processed so it isn't nudged twice.\n\nThis is a v1 focused purely on detection and notification \u2014 it does not auto-book a new slot from the patient's reply. Staff rebook manually based on the replies they receive in WhatsApp. A future version can add automatic rebooking once this core flow is proven.\n\n## How to set up\n1. Create a Supabase project and run the schema in the blue sticky note below.\n2. Add your Supabase credentials in n8n.\n3. Add your Meta WhatsApp Business Cloud API credentials using a permanent system user token.\n4. Create and get approval for a simple text WhatsApp template (e.g. \"Hi {{1}}, you missed your appointment with Dr. {{2}}. Call us or reply here to rebook.\") and set its name in the Send Template node.\n5. Activate the workflow.\n\n## Requirements\n- Supabase project (free tier works)\n- Meta WhatsApp Business Cloud API access with a phone number ID and an approved text template\n- Appointments already logged in the `appointments` table from your booking system\n\n## How to customize\n- Adjust the grace period or polling frequency in the schedule trigger.\n- Add a Slack or email notification to staff alongside the patient nudge.\n- Extend this into an auto-rebooking version by adding a reply-handling step once you're ready."
      },
      "typeVersion": 1
    },
    {
      "id": "95debba2-7b3c-4a36-806e-1f3a0846feca",
      "name": "Schema reference",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        976
      ],
      "parameters": {
        "color": 4,
        "width": 524,
        "height": 360,
        "content": "### Supabase schema needed\n\n```sql\ncreate table appointments (\n  id uuid primary key default gen_random_uuid(),\n  patient_name text not null,\n  patient_phone text not null,\n  doctor_name text not null,\n  appointment_time timestamptz not null,\n  checked_in boolean default false,\n  no_show_processed boolean default false,\n  status text default 'scheduled',\n  created_at timestamptz default now()\n);\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "4a973550-352f-488b-96ed-64f6fc6a8a76",
      "name": "Step 1 note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        656
      ],
      "parameters": {
        "color": 0,
        "width": 260,
        "height": 212,
        "content": "### Step 1\nRuns every 15 minutes. Adjust the interval based on how time-sensitive rebooking is for your clinic."
      },
      "typeVersion": 1
    },
    {
      "id": "a41b75c0-948a-4d08-a8a5-3992d8a520ac",
      "name": "Step 2 note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        656
      ],
      "parameters": {
        "color": 0,
        "width": 280,
        "height": 232,
        "content": "### Step 2\nQueries Supabase for appointments with no check-in and not yet processed for a no-show nudge."
      },
      "typeVersion": 1
    },
    {
      "id": "65953bc6-da2d-4393-9085-512a5c2bf796",
      "name": "Step 3 note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        640
      ],
      "parameters": {
        "color": 0,
        "width": 260,
        "height": 196,
        "content": "### Step 3\nFilters to only appointments where the 30-minute grace period has fully passed."
      },
      "typeVersion": 1
    },
    {
      "id": "959939c6-414e-48f5-baad-48b08e8bf7e0",
      "name": "Step 4 note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1712,
        640
      ],
      "parameters": {
        "color": 0,
        "width": 280,
        "height": 200,
        "content": "### Step 4\nSends the approved WhatsApp template letting the patient know they missed their appointment."
      },
      "typeVersion": 1
    },
    {
      "id": "e0511811-a93d-41dc-b99e-b81303fb5c67",
      "name": "Step 5 note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2096,
        640
      ],
      "parameters": {
        "color": 0,
        "width": 260,
        "height": 212,
        "content": "### Step 5\nMarks the appointment as processed so it's not nudged again on the next run."
      },
      "typeVersion": 1
    },
    {
      "id": "aa085db8-babc-427a-a1ca-57ecad67dd00",
      "name": "Every 15 mins",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        576,
        464
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 15
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "206c3df0-c4d4-4a24-8f80-12797793fdd2",
      "name": "Get Unprocessed Appointments",
      "type": "n8n-nodes-base.supabase",
      "position": [
        960,
        464
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "checked_in",
              "keyValue": "false",
              "condition": "eq"
            },
            {
              "keyName": "no_show_processed",
              "keyValue": "false",
              "condition": "eq"
            }
          ]
        },
        "tableId": "appointments",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e2184e2d-8e8e-4663-9f25-0a7b3db05e07",
      "name": "Past (30 mins) grace period",
      "type": "n8n-nodes-base.filter",
      "position": [
        1280,
        464
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "05233326-1cb7-4835-b998-106cc9f1c7a3",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "leftValue": "={{ new Date($json.appointment_time).getTime() + 30 * 60 * 1000 }}",
              "rightValue": "={{ Date.now() }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "482ca817-0e4c-460e-bb92-c7b6d2acfc97",
      "name": "Loop Over (no-shows)",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1520,
        464
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "ac0dd442-39bb-426a-b8ac-18be5e5722a7",
      "name": "Send WhatsApp (no-show) nudge",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        1792,
        448
      ],
      "parameters": {
        "template": "REPLACE_WITH_YOUR_APPROVED_TEMPLATE_NAME",
        "components": {
          "component": [
            {}
          ]
        },
        "phoneNumberId": "REPLACE_WITH_YOUR_PHONE_NUMBER_ID",
        "recipientPhoneNumber": "={{ $json.patient_phone }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5057e5c8-9666-4cd2-bd25-a6084d16cf1d",
      "name": "Mark appointment as processed",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2160,
        448
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "keyValue": "={{ $('Loop Over (no-shows)').item.json.id }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "appointments",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "checked_in",
              "fieldValue": "true"
            },
            {
              "fieldId": "no_show_processed",
              "fieldValue": "true"
            }
          ]
        },
        "operation": "update"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "timeSavedMode": "fixed",
    "availableInMCP": false,
    "executionOrder": "v1",
    "executionTimeout": -1
  },
  "versionId": "da5e0646-8eca-42a3-83cd-e874a7f79035",
  "nodeGroups": [],
  "connections": {
    "Every 15 mins": {
      "main": [
        [
          {
            "node": "Get Unprocessed Appointments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over (no-shows)": {
      "main": [
        [
          {
            "node": "Send WhatsApp (no-show) nudge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Past (30 mins) grace period": {
      "main": [
        [
          {
            "node": "Loop Over (no-shows)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Unprocessed Appointments": {
      "main": [
        [
          {
            "node": "Past (30 mins) grace period",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send WhatsApp (no-show) nudge": {
      "main": [
        [
          {
            "node": "Mark appointment as processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

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

This workflow runs every 15 minutes to find unprocessed clinic appointments in Supabase that are more than 30 minutes past their scheduled time and sends a WhatsApp Business template message to the patient to prompt rebooking, then flags the appointment so it is not messaged…

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

More Slack & Telegram workflows → · Browse all categories →

Related workflows

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

Slack & Telegram

This workflow runs daily to pull gym members from Supabase, calculate membership expiry and check-in activity, and send WhatsApp messages for renewal reminders, trainer inactivity alerts, and check-in

Supabase, WhatsApp
Slack & Telegram

This workflow runs daily to fetch pending student fee records from Supabase, filters fees due in three days, and sends WhatsApp Business template reminders via the Meta WhatsApp Cloud API, then update

WhatsApp, Supabase
Slack & Telegram

Wait Schedule. Uses spotify, supabase, compareDatasets, noOp. Scheduled trigger; 54 nodes.

Spotify, Supabase, YouTube +1
Slack & Telegram

This workflow is designed for **customer support teams, e-commerce founders, and operations managers** who want to handle thousands of customer queries seamlessly. Instead of building a brand-new chat

Telegram Trigger, Supabase, WhatsApp +2
Slack & Telegram

Regua-De-Cobrancas. Uses httpRequest, emailSend, whatsApp, twilio. Scheduled trigger; 25 nodes.

HTTP Request, Email Send, WhatsApp +2