{
  "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
          }
        ]
      ]
    }
  }
}