{
  "id": "FtpbRCegncW8eK59",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Route home-service requests by urgency over WhatsApp",
  "tags": [],
  "nodes": [
    {
      "id": "bb22ec94-1cdf-4e90-a6c2-2f2c80e118f2",
      "name": "Template Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        0
      ],
      "parameters": {
        "color": 4,
        "width": 680,
        "height": 1072,
        "content": "## \ud83d\udd27 Route Home-Service Requests by Urgency\n\n## Who's it for\nElectricians, plumbers, AC repair technicians, and similar home-service businesses that take requests over WhatsApp and want emergencies handled immediately while routine requests get queued up properly instead of mixed in with everything else.\n\n## How it works\nWhen a customer messages in, AI extracts the issue type, urgency, and location from their message. Every request is logged regardless of urgency. Emergency requests immediately ping your on-call technician with the details and send the customer a confirmation that help is on the way. Routine requests are added to a service queue sheet instead, and the customer gets a message letting them know when to expect a callback, so nothing urgent gets buried in a backlog and nothing routine gets treated like a fire drill.\n\n## How to set up\n1. Connect your WhatsApp Business Cloud credentials to the trigger and both send nodes.\n2. Connect your Groq or Gemini API credentials to the Chat Model node.\n3. Connect your Supabase credentials and create the table described in the sticky note near the Log Request node.\n4. Connect your Google Sheets credentials and create a queue sheet with the columns listed near the Add to Queue node.\n5. Open the Set Configuration node and fill in your WhatsApp phone number ID, on-call technician's number, Sheet ID, and response window.\n6. Activate the workflow.\n\n## Requirements\n- WhatsApp Business Cloud API access\n- Groq or Gemini API key\n- Supabase project\n- Google Sheets account\n\n## How to customize\nEdit the classification prompt to change what counts as an emergency for your trade (e.g. \"no hot water\" might be routine for a plumber but urgent in winter). Update the on-call technician's number as your rotation changes."
      },
      "typeVersion": 1
    },
    {
      "id": "69c115c7-fa19-4490-a311-5776f3292b89",
      "name": "Section - Trigger and Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 508,
        "height": 316,
        "content": "## 1\ufe0f\u20e3 2\ufe0f\u20e3 Trigger + Configuration\nFires on every incoming WhatsApp message."
      },
      "typeVersion": 1
    },
    {
      "id": "350c8d1b-127c-4ad9-b12c-b44b8c40531f",
      "name": "Section - AI Extraction",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        336
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 572,
        "content": "## 3\ufe0f\u20e3 AI Extraction\nDecides issue type, urgency, and location from the customer's message. Edit the prompt to match what counts as an emergency for your trade."
      },
      "typeVersion": 1
    },
    {
      "id": "ca6c33fc-15b5-4170-869b-cc5ae8972e0a",
      "name": "Supabase Schema Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        336
      ],
      "parameters": {
        "color": 3,
        "width": 300,
        "content": "\u26a0\ufe0f Table schema\nservice_requests: customer_name, customer_number, issue_type, location, description, urgency, created_at (timestamptz, default now())."
      },
      "typeVersion": 1
    },
    {
      "id": "2db54ccc-df90-43fe-8d40-1d9a8a0bba0c",
      "name": "Section - Emergency Branch",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 516,
        "content": "## 4\ufe0f\u20e3 If Emergency\nThe on-call technician gets pinged immediately with the details, and the customer gets confirmation that help is coming, both happen in parallel, not one waiting on the other."
      },
      "typeVersion": 1
    },
    {
      "id": "d1c8fce5-02af-45ab-8b11-895510a33459",
      "name": "Extract Request Details",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1216,
        528
      ],
      "parameters": {
        "text": "=Read this home-service request and extract the details.\n\nMessage: {{ $('Set Configuration').item.json.customer_message }}\n\nExtract: issue_type (a short label like \"electrical outage\", \"water leak\", \"AC not cooling\"), location (if mentioned, otherwise \"not specified\"), and a one-sentence description. Also decide urgency: \"emergency\" if this needs attention within hours (safety risk, total outage, active flooding/leak), or \"routine\" if it can reasonably wait a day or two.",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.8
    },
    {
      "id": "848ed36e-4d8f-46d0-9b1d-1b52fcffe530",
      "name": "Extraction Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "position": [
        1184,
        736
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "771d07e5-b30a-4ce3-a8b4-b119a58c32d0",
      "name": "Extraction Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1392,
        752
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"issue_type\": {\n      \"type\": \"string\"\n    },\n    \"location\": {\n      \"type\": \"string\"\n    },\n    \"description\": {\n      \"type\": \"string\"\n    },\n    \"urgency\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"emergency\",\n        \"routine\"\n      ]\n    }\n  },\n  \"required\": [\n    \"issue_type\",\n    \"location\",\n    \"description\",\n    \"urgency\"\n  ]\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "f87a7e94-fc36-4ea1-81b6-a8657174567f",
      "name": "Log Request",
      "type": "n8n-nodes-base.supabase",
      "position": [
        1680,
        528
      ],
      "parameters": {
        "operation": "insert"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6a37968f-3d12-4c99-bf83-f4e90ddc74d3",
      "name": "Is Emergency?",
      "type": "n8n-nodes-base.if",
      "position": [
        1904,
        528
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('Extract Request Details').item.json.output.urgency }}",
              "rightValue": "emergency"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fb7baa31-d484-4b29-98a5-d162a296d56b",
      "name": "Notify On-Call Technician",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        2288,
        240
      ],
      "parameters": {
        "textBody": "=EMERGENCY: {{ $('Extract Request Details').item.json.output.issue_type }} at {{ $('Extract Request Details').item.json.output.location }}. {{ $('Extract Request Details').item.json.output.description }} Customer: {{ $('Set Configuration').item.json.customer_name }}, {{ $('Set Configuration').item.json.customer_number }}",
        "operation": "send",
        "phoneNumberId": "={{ $('Set Configuration').item.json.whatsapp_phone_number_id }}",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration').item.json.oncall_technician_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7c9ab878-059b-4783-9c1a-8c7ccba01925",
      "name": "Confirm Emergency to Customer",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        2288,
        416
      ],
      "parameters": {
        "textBody": "=Got it, this sounds urgent. Our technician has been notified and will call you shortly to confirm arrival time.",
        "operation": "send",
        "phoneNumberId": "={{ $('Set Configuration').item.json.whatsapp_phone_number_id }}",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration').item.json.customer_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3b1319a0-391b-44bd-b971-79cf457c2341",
      "name": "Add to Service Queue",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2384,
        864
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "queued",
            "location": "={{ $('Extract Request Details').item.json.output.location }}",
            "issue_type": "={{ $('Extract Request Details').item.json.output.issue_type }}",
            "description": "={{ $('Extract Request Details').item.json.output.description }}",
            "customer_name": "={{ $('Set Configuration').item.json.customer_name }}",
            "customer_number": "={{ $('Set Configuration').item.json.customer_number }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.queue_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.sheet_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "1ab29097-74d0-4e4e-842e-7e918384c13f",
      "name": "Confirm Queued to Customer",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        2400,
        1024
      ],
      "parameters": {
        "textBody": "=Thanks for reaching out! We've added your request ({{ $('Extract Request Details').item.json.output.issue_type }}) to our queue and will contact you within {{ $('Set Configuration').item.json.routine_response_days }} days to schedule a visit.",
        "operation": "send",
        "phoneNumberId": "={{ $('Set Configuration').item.json.whatsapp_phone_number_id }}",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration').item.json.customer_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f77eedab-fd72-4b9a-8c61-2c2b12baded6",
      "name": "New Service Request",
      "type": "n8n-nodes-base.whatsAppTrigger",
      "position": [
        656,
        528
      ],
      "parameters": {
        "options": {},
        "updates": [
          "messages"
        ]
      },
      "credentials": {
        "whatsAppTriggerApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5e7994d3-aba2-478b-a1cf-d226cfa01fc9",
      "name": "Set Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        880,
        528
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1bfb8edb-7ece-43ef-bdbe-d8fbc1eaec80",
              "name": "business_name",
              "type": "string",
              "value": "REPLACE_WITH_BUSINESS_NAME"
            },
            {
              "id": "8024c167-c84e-469a-99f1-60c90b83a554",
              "name": "whatsapp_phone_number_id",
              "type": "string",
              "value": "REPLACE_WITH_WHATSAPP_PHONE_NUMBER_ID"
            },
            {
              "id": "f39a7248-b2a0-4927-b0dd-50923627b1b0",
              "name": "oncall_technician_number",
              "type": "string",
              "value": "REPLACE_WITH_TECHNICIAN_WHATSAPP_NUMBER"
            },
            {
              "id": "d8e6bae5-7c08-47aa-8860-c7d087935efe",
              "name": "supabase_table_requests",
              "type": "string",
              "value": "service_requests"
            },
            {
              "id": "59f47b46-97b1-45e2-8e29-2bf22b281efc",
              "name": "sheet_id",
              "type": "string",
              "value": "REPLACE_WITH_GOOGLE_SHEET_ID"
            },
            {
              "id": "302e7185-9e12-4897-b80a-d811f6991d53",
              "name": "queue_sheet_name",
              "type": "string",
              "value": "Queue"
            },
            {
              "id": "5d8332fc-8a19-41c6-8b60-5eb6feaa8290",
              "name": "routine_response_days",
              "type": "number",
              "value": 2
            },
            {
              "id": "d50ce126-7ade-4a47-8268-5ebb47f82af4",
              "name": "customer_message",
              "type": "string",
              "value": "={{ $json.messages[0].text.body }}"
            },
            {
              "id": "ba5ce2d1-9bc7-45cf-ba04-68044ceaa82c",
              "name": "customer_number",
              "type": "string",
              "value": "={{ $json.messages[0].from }}"
            },
            {
              "id": "49232585-66ea-4182-a068-331f109fb4f1",
              "name": "customer_name",
              "type": "string",
              "value": "={{ $json.contacts[0].profile.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c0116245-5ddd-43c7-bede-5d9a0e43685b",
      "name": "Section - Emergency Branch1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        640
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 564,
        "content": "## 5\ufe0f\u20e3 If Routine\nAdded to the service queue sheet instead of triggering an immediate response, then the customer gets a realistic timeframe rather than being left wondering."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "bab98f81-3d6f-4a57-971f-0cefd7e54411",
  "nodeGroups": [],
  "connections": {
    "Log Request": {
      "main": [
        [
          {
            "node": "Is Emergency?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Emergency?": {
      "main": [
        [
          {
            "node": "Notify On-Call Technician",
            "type": "main",
            "index": 0
          },
          {
            "node": "Confirm Emergency to Customer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Add to Service Queue",
            "type": "main",
            "index": 0
          },
          {
            "node": "Confirm Queued to Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extraction Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Extract Request Details",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration": {
      "main": [
        [
          {
            "node": "Extract Request Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Service Request": {
      "main": [
        [
          {
            "node": "Set Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extraction Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Extract Request Details",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract Request Details": {
      "main": [
        [
          {
            "node": "Log Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}