{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "f4fb7638-36e1-4b7c-a661-d7153a46af03",
      "name": "Skip - Call Was Answered",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -416,
        560
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "458423f0-bbe4-45cd-a9ec-1a466e6381d9",
      "name": "Receive Missed Call Webhook",
      "type": "n8n-nodes-base.webhook",
      "notes": "No worker available",
      "position": [
        -864,
        464
      ],
      "parameters": {
        "path": "missed-calls",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "72cd9de6-675f-47c6-9f2f-e5b6c13da36b",
      "name": "Check Call Failed/Busy/No-Answer",
      "type": "n8n-nodes-base.if",
      "position": [
        -640,
        464
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "72ae5243-9563-4ec1-b958-c66289082ebc",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.CallStatus }}",
              "rightValue": "no-answer"
            },
            {
              "id": "9c9d2c61-e6e4-4e16-829c-798eb19335fe",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.CallStatus }}",
              "rightValue": "busy"
            },
            {
              "id": "dc546949-4d0f-4f9a-a662-cc73e3021c69",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.CallStatus }}",
              "rightValue": "failed"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "f4838746-3f2e-47fe-887f-ab1cecdfb2db",
      "name": "Check Business Hours",
      "type": "n8n-nodes-base.code",
      "position": [
        -416,
        368
      ],
      "parameters": {
        "jsCode": "// Use n8n's built-in $now which respects the n8n instance timezone\n// Set your timezone in n8n Settings > General > Timezone\nconst now = new Date();\n\n// Convert to your business timezone without luxon\nconst formatter = new Intl.DateTimeFormat('en-US', {\n  timeZone: 'America/New_York', // Change to your timezone\n  weekday: 'short',\n  hour: 'numeric',\n  hour12: false\n});\n\nconst parts = formatter.formatToParts(now);\nconst weekday = parts.find(p => p.type === 'weekday').value; // 'Mon', 'Tue', etc.\nconst hour = parseInt(parts.find(p => p.type === 'hour').value);\n\nconst isWeekday = !['Sat', 'Sun'].includes(weekday);\nconst isWorkingHour = hour >= 9 && hour < 17;\n\nreturn {\n  isBusinessHours: isWeekday && isWorkingHour\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "0819503f-36dd-421d-9a49-48a99b9314ad",
      "name": "Log Missed Call to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -192,
        368
      ],
      "parameters": {
        "columns": {
          "value": {
            "To": "={{ $('Receive Missed Call Webhook').item.json.To }}",
            "SID": "={{ $('Receive Missed Call Webhook').item.json.CallSid }}",
            "Time": "={{ $now }}",
            "Direction": "={{ $('Receive Missed Call Webhook').item.json.Direction }}",
            "CallStatus": "={{ $('Receive Missed Call Webhook').item.json.CallStatus }}",
            "Lead Number": "={{ $('Receive Missed Call Webhook').item.json.From }}"
          },
          "schema": [
            {
              "id": "SID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "SID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Lead Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Lead Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "To",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "To",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "CallStatus",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "CallStatus",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Direction",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Direction",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Time",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KJ4-6cNZduk71GyNVykqvg0_07VFn8eYsFUKEuwX-lQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1KJ4-6cNZduk71GyNVykqvg0_07VFn8eYsFUKEuwX-lQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KJ4-6cNZduk71GyNVykqvg0_07VFn8eYsFUKEuwX-lQ/edit?usp=drivesdk",
          "cachedResultName": "Missed call recovery system"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "3f9cc7ed-8fc5-4833-97a1-d5b0109ad9ab",
      "name": "Is It Business Hours?",
      "type": "n8n-nodes-base.if",
      "position": [
        32,
        368
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7d6cd1e2-e0f4-4a21-9ee0-696936514119",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $('Check Business Hours').item.json.isBusinessHours }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d022f704-5e65-4f30-be39-86597a502a8d",
      "name": "SMS - Call Back in 5 Minutes",
      "type": "n8n-nodes-base.twilio",
      "position": [
        256,
        272
      ],
      "parameters": {
        "to": "={{ $('Receive Missed Call Webhook').item.json.From }}",
        "from": "={{ $('Receive Missed Call Webhook').item.json.To }}",
        "message": "=Hi, we noticed your call. We missed it and will call you back as soon as possible, usually within the hour. Reply YES to confirm you are still available, or call us anytime at {{ $('Receive Missed Call Webhook').item.json.To }}. Reply STOP to opt out.",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "71b26c9e-a542-4355-9364-cd2312fc8326",
      "name": "SMS - Will Contact in Business Hours",
      "type": "n8n-nodes-base.twilio",
      "position": [
        256,
        464
      ],
      "parameters": {
        "to": "={{ $('Receive Missed Call Webhook').item.json.From }}",
        "from": "={{ $('Receive Missed Call Webhook').item.json.To }}",
        "message": "=Hi, we noticed your call. Our team is currently outside business hours, Monday to Friday, 9am to 5pm ET. We will reach out first thing on the next business day. You can also call us back at {{ $('Receive Missed Call Webhook').item.json.To }}. Reply STOP to opt out.",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "10303795-754a-449e-a2d7-0faa911f0318",
      "name": "Notify Team on Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        480,
        368
      ],
      "parameters": {
        "text": "=Missed call from {{ $('Receive Missed Call Webhook').item.json.From }} at {{ $now.format('hh:mm a') }}. Click to call back.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0ABBRA98R3",
          "cachedResultName": "new-channel"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "fd720c49-849f-49c1-b144-74862aa40a61",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        16
      ],
      "parameters": {
        "width": 512,
        "height": 800,
        "content": "This workflow automatically recovers missed inbound calls so no potential lead is lost.\n\nWhen a call is missed in Twilio, the workflow captures the event, checks the call status, determines whether it occurred during business hours, logs the call to Google Sheets, sends an automatic SMS to the caller, and notifies your team in Slack.\n\nIt ensures callers receive immediate acknowledgment and your team has visibility for follow up.\n\n## How it works\n\n- Receives inbound call events from Twilio\n\n- Filters for failed, busy, or no answer calls\n\n- Checks whether the call happened during business hours\n\n- Logs call details to Google Sheets\n\n- Sends an SMS reply based on business hours\n\n- Notifies your team in Slack\n\n## Setup steps\n\n- Connect your Twilio account and set the webhook URL\n\n- Connect Google Sheets and choose your tracking sheet\n\n- Connect Slack and select a notification channel\n\n- Adjust business hours and timezone in the code node\n\n- Customize the SMS message if needed"
      },
      "typeVersion": 1
    },
    {
      "id": "c580a6c2-5def-4375-8a54-0a521391c35a",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 624,
        "content": "## Call intake and filtering\n\nReceives inbound call events from Twilio via webhook. Filters for missed, busy, or failed calls and ignores answered ones. Only valid missed calls continue through the recovery flow to prevent unnecessary messages or notifications."
      },
      "typeVersion": 1
    },
    {
      "id": "9b4f1235-3327-46dd-96eb-3c1bafbe5f3f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -464,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 432,
        "content": "## Logging and business hour check\n\nLogs missed call details to Google Sheets for tracking and reporting. Then checks whether the call occurred during defined business hours to determine the correct SMS response logic."
      },
      "typeVersion": 1
    },
    {
      "id": "e358376d-2321-4fa9-bfcc-276602ab648b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 544,
        "content": "## Automated SMS and team notification\n\nSends an automatic SMS to the caller based on business hours, either promising a quick callback or setting next day expectations. Notifies the team in Slack with caller details so follow up can happen immediately."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Check Business Hours": {
      "main": [
        [
          {
            "node": "Log Missed Call to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is It Business Hours?": {
      "main": [
        [
          {
            "node": "SMS - Call Back in 5 Minutes",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "SMS - Will Contact in Business Hours",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Missed Call Webhook": {
      "main": [
        [
          {
            "node": "Check Call Failed/Busy/No-Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SMS - Call Back in 5 Minutes": {
      "main": [
        [
          {
            "node": "Notify Team on Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Call Failed/Busy/No-Answer": {
      "main": [
        [
          {
            "node": "Check Business Hours",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Skip - Call Was Answered",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Missed Call to Google Sheets": {
      "main": [
        [
          {
            "node": "Is It Business Hours?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SMS - Will Contact in Business Hours": {
      "main": [
        [
          {
            "node": "Notify Team on Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}