{
  "name": "WF-02 · Missed-Call Rescue",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "missed-call",
        "responseMode": "onReceived",
        "options": {}
      },
      "id": "n1",
      "name": "Missed Call Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [200, 300],
      "webhookId": "missed-call-trigger",
      "notes": "Configure your phone system (JustCall, Twilio, OpenPhone, etc.) to POST to this URL when a call goes unanswered. Payload should include: caller_number, call_time, call_direction."
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            { "id": "1", "name": "callerNumber", "value": "={{ $json.caller_number || $json.from || $json.CallerNumber }}", "type": "string" },
            { "id": "2", "name": "callTime",     "value": "={{ $json.call_time || $now }}", "type": "string" },
            { "id": "3", "name": "missedAt",     "value": "={{ $now }}", "type": "string" }
          ]
        },
        "options": {}
      },
      "id": "n2",
      "name": "Parse Call Data",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [420, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/objects/contacts/search",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "Bearer {{ HUBSPOT_PRIVATE_APP_TOKEN }}" }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"filterGroups\": [{\n    \"filters\": [{\n      \"propertyName\": \"phone\",\n      \"operator\": \"EQ\",\n      \"value\": \"{{ $json.callerNumber }}\"\n    }]\n  }],\n  \"properties\": [\"firstname\", \"lastname\", \"email\", \"phone\", \"hs_lead_status\"]\n}",
        "options": {}
      },
      "id": "n3",
      "name": "Lookup Caller in CRM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [640, 300]
    },
    {
      "parameters": {
        "amount": 10,
        "unit": "seconds"
      },
      "id": "n4",
      "name": "Wait 10 Seconds",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [860, 300]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $('Lookup Caller in CRM').item.json.total }}",
              "rightValue": 0,
              "operator": { "type": "number", "operation": "gt" }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "n5",
      "name": "Known Contact?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1060, 300]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            { "id": "1", "name": "greeting", "value": "=Hi {{ $('Lookup Caller in CRM').item.json.results[0].properties.firstname }}", "type": "string" }
          ]
        },
        "options": {}
      },
      "id": "n6",
      "name": "Personalize Greeting",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [1260, 180]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            { "id": "1", "name": "greeting", "value": "Hi there", "type": "string" }
          ]
        },
        "options": {}
      },
      "id": "n7",
      "name": "Generic Greeting",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [1260, 420]
    },
    {
      "parameters": {
        "mode": "passThrough",
        "output": "input1"
      },
      "id": "n8",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [1460, 300]
    },
    {
      "parameters": {
        "operation": "send",
        "from": "{{ YOUR_TWILIO_PHONE_NUMBER }}",
        "to": "={{ $('Parse Call Data').item.json.callerNumber }}",
        "message": "={{ $json.greeting }} — sorry we missed your call! This is {{ YOUR_BUSINESS_NAME }}. How can we help? Reply here or call us back at {{ YOUR_PHONE_NUMBER }}."
      },
      "id": "n9",
      "name": "Send Text-Back SMS",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [1660, 180],
      "credentials": {
        "twilioApi": { "id": "twilio-creds", "name": "Twilio" }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/objects/notes",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "Bearer {{ HUBSPOT_PRIVATE_APP_TOKEN }}" }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"properties\": {\n    \"hs_note_body\": \"Missed inbound call from {{ $('Parse Call Data').item.json.callerNumber }} at {{ $('Parse Call Data').item.json.missedAt }}. Text-back sent automatically.\",\n    \"hs_timestamp\": \"{{ $('Parse Call Data').item.json.missedAt }}\"\n  }\n}",
        "options": {}
      },
      "id": "n10",
      "name": "Log Missed Call in CRM",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [1660, 320]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.hubapi.com/crm/v3/objects/calls?callerNumber={{ $('Parse Call Data').item.json.callerNumber }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "Bearer {{ HUBSPOT_PRIVATE_APP_TOKEN }}" }
          ]
        },
        "options": {},
        "notes": "Replace with your voicemail/transcription provider endpoint. Works with JustCall, OpenPhone, or Fireflies.ai webhook payloads."
      },
      "id": "n11",
      "name": "Fetch Voicemail Transcript",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [1660, 460]
    },
    {
      "parameters": {
        "sendTo": "{{ YOUR_EMAIL }}",
        "subject": "=Missed call from {{ $('Parse Call Data').item.json.callerNumber }}",
        "emailType": "html",
        "message": "=<p>You missed a call from <strong>{{ $('Parse Call Data').item.json.callerNumber }}</strong> at {{ $('Parse Call Data').item.json.missedAt }}.</p><p>A text-back was sent automatically.</p><p><strong>Voicemail summary:</strong><br>{{ $('Fetch Voicemail Transcript').item.json.transcription || 'No voicemail left.' }}</p>",
        "options": {}
      },
      "id": "n12",
      "name": "Email Summary to Rep",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [1880, 320],
      "credentials": {
        "gmailOAuth2": { "id": "gmail-creds", "name": "Gmail" }
      }
    }
  ],
  "connections": {
    "Missed Call Webhook":     { "main": [[{ "node": "Parse Call Data",           "type": "main", "index": 0 }]] },
    "Parse Call Data":         { "main": [[{ "node": "Lookup Caller in CRM",      "type": "main", "index": 0 }]] },
    "Lookup Caller in CRM":    { "main": [[{ "node": "Wait 10 Seconds",            "type": "main", "index": 0 }]] },
    "Wait 10 Seconds":         { "main": [[{ "node": "Known Contact?",             "type": "main", "index": 0 }]] },
    "Known Contact?": {
      "main": [
        [{ "node": "Personalize Greeting", "type": "main", "index": 0 }],
        [{ "node": "Generic Greeting",     "type": "main", "index": 0 }]
      ]
    },
    "Personalize Greeting": { "main": [[{ "node": "Merge", "type": "main", "index": 0 }]] },
    "Generic Greeting":     { "main": [[{ "node": "Merge", "type": "main", "index": 1 }]] },
    "Merge": {
      "main": [[
        { "node": "Send Text-Back SMS",       "type": "main", "index": 0 },
        { "node": "Log Missed Call in CRM",   "type": "main", "index": 0 },
        { "node": "Fetch Voicemail Transcript","type": "main", "index": 0 }
      ]]
    },
    "Fetch Voicemail Transcript": { "main": [[{ "node": "Email Summary to Rep", "type": "main", "index": 0 }]] }
  },
  "active": false,
  "settings": { "executionOrder": "v1" },
  "id": "wf-02-missed-call-rescue",
  "versionId": "1.0.0"
}
