Skip to content

Instantly share code, notes, and snippets.

@iamvaar-dev
Created July 1, 2026 18:29
Show Gist options
  • Select an option

  • Save iamvaar-dev/0b704a24213725bf83d2f2399d699696 to your computer and use it in GitHub Desktop.

Select an option

Save iamvaar-dev/0b704a24213725bf83d2f2399d699696 to your computer and use it in GitHub Desktop.
Automated Pet Vacination Reminder
{
"nodes": [
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "9f5e9804-1607-4a24-98e2-cf2bdcd2b0c4",
"name": "3 days from now",
"value": "={{ DateTime.now().plus({ days: 3 }).toISODate() }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
624,
80
],
"id": "ed3f1259-d56b-4fa6-b826-8eeb4af3fda4",
"name": "Edit Fields"
},
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 11
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [
400,
80
],
"id": "bbd2a7c4-29ae-4ab5-b2da-058dbcc43109",
"name": "Schedule Trigger"
},
{
"parameters": {
"content": "# Vaccination Stage Logic\n\n| `current_stage` | Meaning | Next due date rule |\n|-------------------|-----------------------------------|----------------------------------------------|\n| `none` | No shots yet | `pet_dob + 49 days` (7 weeks) |\n| `puppy_1` | 1st puppy shot done | `last_vaccination_date + 28 days` |\n| `puppy_2` | 2nd puppy shot done | `last_vaccination_date + 28 days` |\n| `puppy_3` | 3rd puppy shot done | `last_vaccination_date + 1 year` |\n| `adult_1yr` | 1-year booster done | `last_vaccination_date + 1 year` |\n| `adult_booster` | Any later annual booster done | `last_vaccination_date + 1 year` (loops forever) |",
"height": 368,
"width": 752
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
880,
-352
],
"id": "b63fa563-c45c-4616-ace4-0298fa3f0028",
"name": "Sticky Note"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "177a50df-b6cf-41d2-b961-1661a63ecdee",
"leftValue": "={{ $json.dnd }}",
"rightValue": false,
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
1728,
64
],
"id": "565e4272-32b1-43be-a6fa-8e4c19698525",
"name": "If1"
},
{
"parameters": {
"operation": "getAll",
"tableId": "pet_vaccinations",
"returnAll": true
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
832,
80
],
"id": "074c0dea-7ab6-4c32-8983-8b8abfbbe432",
"name": "Get Pet Vacination Records",
"credentials": {
"supabaseApi": {
"id": "APOX6ME1jBnq4U50",
"name": "VENKIBVB"
}
}
},
{
"parameters": {
"jsCode": "// Get today's date and normalize to midnight for accurate day math\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\n\n// Map the raw stage to a template-friendly format\n// This fits perfectly into the phrase: \"needs [stage] vaccine by...\"\nconst stageNames = {\n 'none': 'their 1st puppy',\n 'puppy_1': 'their 2nd puppy',\n 'puppy_2': 'their 3rd puppy',\n 'puppy_3': 'their 1-year adult',\n 'adult_1yr': 'their annual adult',\n 'adult_booster': 'their annual adult'\n};\n\n// Loop over all incoming items from the previous node\nfor (const item of $input.all()) {\n const data = item.json;\n const stage = data.current_stage;\n \n // Assign the readable text to a new property to use in your template\n data.readable_stage = stageNames[stage] || 'their upcoming';\n \n let nextDueDate = null;\n\n // 1. First shot: 7 weeks after birth\n if (stage === 'none' && data.pet_dob) {\n let dob = new Date(data.pet_dob);\n dob.setDate(dob.getDate() + 49); // 7 weeks * 7 days\n nextDueDate = dob;\n } \n // 2. Puppy boosters: 4 weeks after the last shot\n else if (['puppy_1', 'puppy_2'].includes(stage) && data.last_vaccination_date) {\n let lastDate = new Date(data.last_vaccination_date);\n lastDate.setDate(lastDate.getDate() + 28); // 4 weeks * 7 days\n nextDueDate = lastDate;\n } \n // 3. Annual boosters: 1 year after the last shot\n else if (['puppy_3', 'adult_1yr', 'adult_booster'].includes(stage) && data.last_vaccination_date) {\n let lastDate = new Date(data.last_vaccination_date);\n lastDate.setFullYear(lastDate.getFullYear() + 1); // Add 1 year\n nextDueDate = lastDate;\n }\n\n // Set default contact flags and template\n data.should_contact = false;\n data.contact_reason = null;\n data.message_template = null;\n\n if (nextDueDate) {\n // Format the calculated date as YYYY-MM-DD for database consistency\n const yyyy = nextDueDate.getFullYear();\n const mm = String(nextDueDate.getMonth() + 1).padStart(2, '0');\n const dd = String(nextDueDate.getDate()).padStart(2, '0');\n \n data.next_due_date = `${yyyy}-${mm}-${dd}`;\n\n // Normalize nextDueDate to midnight to compare cleanly with 'today'\n const normalizedDue = new Date(yyyy, nextDueDate.getMonth(), nextDueDate.getDate());\n normalizedDue.setHours(0, 0, 0, 0);\n\n // Calculate difference in days between due date and today\n const msPerDay = 1000 * 60 * 60 * 24;\n const diffDays = Math.round((normalizedDue.getTime() - today.getTime()) / msPerDay);\n\n // LOGIC 1: Due in 3 days or less (and not yet passed)\n if (diffDays >= 0 && diffDays <= 3) {\n data.should_contact = true;\n data.contact_reason = diffDays === 0 ? 'due_today' : `due_in_${diffDays}_days`;\n data.message_template = 'whatsapp_single_template'; \n } \n // LOGIC 2: Vaccination date has passed\n else if (diffDays < 0) {\n const daysOverdue = Math.abs(diffDays);\n\n // Contact exactly on the 1-month, 2-month, and 3-month marks\n if (daysOverdue === 30 || daysOverdue === 60 || daysOverdue === 90) {\n data.should_contact = true;\n data.contact_reason = `overdue_${daysOverdue}_days`;\n data.message_template = 'whatsapp_single_template';\n } else if (daysOverdue > 90) {\n data.contact_reason = 'lost_to_follow_up';\n } else {\n data.contact_reason = 'overdue_waiting';\n }\n }\n } else {\n data.next_due_date = null; \n }\n}\n\nreturn $input.all();"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1040,
80
],
"id": "faaa0b12-720b-46ff-b54d-f929100d8956",
"name": "Filter Vaccine Eligible Pets"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "b3e43924-0089-4ec9-86a6-e1f125ac84c5",
"leftValue": "={{ $json.should_contact }}",
"rightValue": false,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
1248,
80
],
"id": "5231f27f-3a81-4a27-8516-223a14aa5d8d",
"name": "validate the eligibility"
},
{
"parameters": {
"operation": "getAll",
"tableId": "pet_parents",
"filters": {
"conditions": [
{
"keyName": "phone",
"condition": "eq",
"keyValue": "={{ $json.phone }}"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
1520,
64
],
"id": "9bed07d8-1b10-44de-9420-857f49432db1",
"name": "Check pet parent is on DND mode",
"credentials": {
"supabaseApi": {
"id": "APOX6ME1jBnq4U50",
"name": "VENKIBVB"
}
}
},
{
"parameters": {
"operation": "send",
"phoneNumberId": "1083481144853090",
"recipientPhoneNumber": "={{ $json.phone }}",
"textBody": "=Hi {{ $json.parent_name }}! 🐾 A quick health update for {{ $('Get Pet Vacination Records').item.json.pet_name }} from Blankarray pet clinic.\n\n{{ $('Get Pet Vacination Records').item.json.pet_name }} needs {{ $('Filter Vaccine Eligible Pets').item.json.readable_stage }} vaccine by {{ $('Get Pet Vacination Records').item.json.next_due_date }}.",
"additionalFields": {}
},
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1.1,
"position": [
1952,
48
],
"id": "421c4e2d-15fa-4f65-83b9-b4bc516f4fa1",
"name": "Send message",
"webhookId": "6f918903-32e8-405d-a968-7f0886a4b699",
"credentials": {
"whatsAppApi": {
"id": "KsIEVWr4quKHUlO7",
"name": "WhatsApp account"
}
}
},
{
"parameters": {
"updates": [
"messages"
],
"options": {}
},
"type": "n8n-nodes-base.whatsAppTrigger",
"typeVersion": 1,
"position": [
400,
336
],
"id": "c9e1373c-0530-4977-9685-d5d8df78b60e",
"name": "WhatsApp Trigger",
"webhookId": "8fba190b-ee4e-42ec-8289-f76c74d85b6b",
"credentials": {
"whatsAppTriggerApi": {
"id": "iXRwfmH8WHEurWCh",
"name": "WhatsApp OAuth account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "650444df-43d5-49f6-b9a3-fb0f636382d9",
"leftValue": "={{ $json.messages[0].text.body }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
}
},
{
"id": "8e635e6f-7d76-4487-9a25-288b32f2cbef",
"leftValue": "={{ $json.messages[0].type }}",
"rightValue": "unsupported",
"operator": {
"type": "string",
"operation": "notEquals"
}
},
{
"id": "4f87efcf-58d6-41ee-be9b-c9d520d37822",
"leftValue": "={{ $json.messages[0].text.body }}",
"rightValue": "STOP",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {
"ignoreCase": true
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
592,
336
],
"id": "b848d80e-6b22-4322-aad5-9e7194ed718f",
"name": "If2"
},
{
"parameters": {
"operation": "update",
"tableId": "pet_parents",
"filters": {
"conditions": [
{
"keyName": "phone",
"condition": "eq",
"keyValue": "={{ $('WhatsApp Trigger').item.json.contacts[0].wa_id }}"
}
]
},
"fieldsUi": {
"fieldValues": [
{
"fieldId": "dnd",
"fieldValue": "TRUE"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
928,
320
],
"id": "9a4403c6-e889-4596-b5d2-7b070eb5d9ac",
"name": "Update a row",
"credentials": {
"supabaseApi": {
"id": "APOX6ME1jBnq4U50",
"name": "VENKIBVB"
}
}
},
{
"parameters": {
"operation": "send",
"phoneNumberId": "1083481144853090",
"recipientPhoneNumber": "={{ $('WhatsApp Trigger').item.json.contacts[0].wa_id }}",
"textBody": "We succesfully put you on DND mode. So no more marketing messages will be sent. Reply back \"START\" to get your pet vaccine reminders",
"additionalFields": {}
},
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1.1,
"position": [
1216,
320
],
"id": "016244d4-33ab-4932-9553-f566269418ee",
"name": "Send message1",
"webhookId": "669fef63-1f6e-4046-9f88-9f2e06d6de24",
"credentials": {
"whatsAppApi": {
"id": "KsIEVWr4quKHUlO7",
"name": "WhatsApp account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "88773ca3-a81b-4a99-8696-cc9f9394fe26",
"leftValue": "={{ $json.messages[0].text.body }}",
"rightValue": "start",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"options": {
"ignoreCase": true
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
816,
512
],
"id": "60aaa43d-cedd-4199-9159-2768a984d6a6",
"name": "If"
},
{
"parameters": {
"operation": "update",
"tableId": "pet_parents",
"filters": {
"conditions": [
{
"keyName": "phone",
"condition": "eq",
"keyValue": "={{ $('WhatsApp Trigger').item.json.contacts[0].wa_id }}"
}
]
},
"fieldsUi": {
"fieldValues": [
{
"fieldId": "dnd",
"fieldValue": "FALSE"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
1056,
496
],
"id": "0686ec5d-13f3-4aef-82c7-42c9f908e657",
"name": "Update a row1",
"credentials": {
"supabaseApi": {
"id": "APOX6ME1jBnq4U50",
"name": "VENKIBVB"
}
}
},
{
"parameters": {
"operation": "send",
"phoneNumberId": "1083481144853090",
"recipientPhoneNumber": "={{ $('WhatsApp Trigger').item.json.contacts[0].wa_id }}",
"textBody": "We succesfully put Lifted DND mode. So you will recieve your pet's vaccination reminders from now. Reply back \"STOP\" if this is a mistake",
"additionalFields": {}
},
"type": "n8n-nodes-base.whatsApp",
"typeVersion": 1.1,
"position": [
1312,
496
],
"id": "84641f7d-a6fd-4877-b7e4-475512e82889",
"name": "Send message2",
"webhookId": "669fef63-1f6e-4046-9f88-9f2e06d6de24",
"credentials": {
"whatsAppApi": {
"id": "KsIEVWr4quKHUlO7",
"name": "WhatsApp account"
}
}
}
],
"connections": {
"Edit Fields": {
"main": [
[
{
"node": "Get Pet Vacination Records",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"If1": {
"main": [
[
{
"node": "Send message",
"type": "main",
"index": 0
}
]
]
},
"Get Pet Vacination Records": {
"main": [
[
{
"node": "Filter Vaccine Eligible Pets",
"type": "main",
"index": 0
}
]
]
},
"Filter Vaccine Eligible Pets": {
"main": [
[
{
"node": "validate the eligibility",
"type": "main",
"index": 0
}
]
]
},
"validate the eligibility": {
"main": [
[
{
"node": "Check pet parent is on DND mode",
"type": "main",
"index": 0
}
]
]
},
"Check pet parent is on DND mode": {
"main": [
[
{
"node": "If1",
"type": "main",
"index": 0
}
]
]
},
"WhatsApp Trigger": {
"main": [
[
{
"node": "If2",
"type": "main",
"index": 0
}
]
]
},
"If2": {
"main": [
[
{
"node": "Update a row",
"type": "main",
"index": 0
}
],
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Update a row": {
"main": [
[
{
"node": "Send message1",
"type": "main",
"index": 0
}
]
]
},
"If": {
"main": [
[
{
"node": "Update a row1",
"type": "main",
"index": 0
}
]
]
},
"Update a row1": {
"main": [
[
{
"node": "Send message2",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "93f396852104089b8670e7494b0f3668b420464668ae4a8c1d6b4b5799f8e3ef"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment