{
  "name": "Missed-call text-back (Barbershops & salons)",
  "nodes": [
    {
      "id": "22496c62-2b47-524b-b90b-39d73cd9342f",
      "name": "Call ended (from Twilio)",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "httpMethod": "POST",
        "path": "missed-call",
        "responseMode": "responseNode",
        "options": {}
      },
      "webhookId": "50e15a98-805d-50c6-aab6-c8f4c19ce8c0"
    },
    {
      "id": "eb476fc6-e1c2-5c33-aad8-f92123f5624d",
      "name": "Incoming text",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        300
      ],
      "parameters": {
        "httpMethod": "POST",
        "path": "incoming-sms",
        "responseMode": "responseNode",
        "options": {}
      },
      "webhookId": "c72675db-64aa-556d-a4e3-f074b2ad5c9e"
    },
    {
      "id": "aaaa59a2-9031-5c94-83c8-843d4c635b69",
      "name": "Config (edit me)",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        220,
        140
      ],
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "1876b74b-a97a-58c8-8b0d-3bce7ad07b54",
              "name": "business_name",
              "value": "YOUR BUSINESS NAME",
              "type": "string"
            },
            {
              "id": "d93da214-5275-5dab-a261-f939a9a48718",
              "name": "booking_link",
              "value": "https://YOUR-BOOKING-LINK",
              "type": "string"
            },
            {
              "id": "9e602375-6901-5523-8719-cabab4e613d4",
              "name": "hours",
              "value": "Mon-Fri 8am-6pm",
              "type": "string"
            },
            {
              "id": "b28d010e-c893-5a44-8681-51fdec735aad",
              "name": "owner_email",
              "value": "you@example.com",
              "type": "string"
            },
            {
              "id": "15ef1a33-f1ec-5276-92a0-314f0dd5ce10",
              "name": "owner_cell",
              "value": "+15555550100",
              "type": "string"
            },
            {
              "id": "4b1510e0-aad1-53e8-881e-aaecdce918d4",
              "name": "twilio_number",
              "value": "+15555550199",
              "type": "string"
            },
            {
              "id": "c309381e-7e55-5f94-a011-69493abcb288",
              "name": "wait_sheet_id",
              "value": "YOUR_GOOGLE_SHEET_ID",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      }
    },
    {
      "id": "ef211055-03e3-5ca6-bd04-7f55b7576bd6",
      "name": "Call or text?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        440,
        140
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "c288b397-e93c-5329-a201-33540eb7386a",
              "leftValue": "={{ $json.body.DialCallStatus }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "89acc9b3-2ab3-524f-8650-678b2df38271",
      "name": "Tell Twilio what to say",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        660,
        0
      ],
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.body.DialCallStatus === 'completed' ? '<Response><Hangup/></Response>' : '<Response><Say>Sorry we missed you. We are texting you right now.</Say><Hangup/></Response>' }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/xml"
              }
            ]
          }
        }
      }
    },
    {
      "id": "f6adb541-c37c-5591-a1cb-bc9fb53d587b",
      "name": "Was the call missed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        880,
        0
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "b0ffdb79-921a-58ea-95ec-b07b029465e4",
              "leftValue": "={{ $('Call ended (from Twilio)').item.json.body.DialCallStatus }}",
              "rightValue": "completed",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "62d02f85-e942-5fe6-8ef0-feed20667a41",
      "name": "Read current wait",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1100,
        0
      ],
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "={{ $('Config (edit me)').item.json.wait_sheet_id }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Wait",
          "mode": "name"
        },
        "options": {}
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "REPLACE_SHEETS_CREDENTIAL",
          "name": "Google Sheets account (placeholder)"
        }
      },
      "alwaysOutputData": true
    },
    {
      "id": "07b60e73-18af-5e7b-be33-e5d7a6f0aeef",
      "name": "Text the caller",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1320,
        0
      ],
      "parameters": {
        "from": "={{ $('Config (edit me)').item.json.twilio_number }}",
        "to": "={{ $('Call ended (from Twilio)').item.json.body.From }}",
        "message": "=Hey, it's {{ $('Config (edit me)').item.json.business_name }}! Sorry we missed you, we're mid-cut. Book your spot here: {{ $('Config (edit me)').item.json.booking_link }} Or walk in: we're open {{ $('Config (edit me)').item.json.hours }}, current wait is about {{ ($('Read current wait').first().json.current_wait || 'ask us') }}.",
        "options": {}
      },
      "credentials": {
        "twilioApi": {
          "id": "REPLACE_TWILIO_CREDENTIAL",
          "name": "Twilio account (placeholder)"
        }
      }
    },
    {
      "id": "9eb05f10-62f0-55ff-b427-e2d03eab8870",
      "name": "Email the owner",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1540,
        0
      ],
      "parameters": {
        "sendTo": "={{ $('Config (edit me)').item.json.owner_email }}",
        "subject": "=Missed call from {{ $('Call ended (from Twilio)').item.json.body.From }}",
        "emailType": "text",
        "message": "=We missed a call from {{ $('Call ended (from Twilio)').item.json.body.From }} and texted them automatically. Call them back when you can.",
        "options": {}
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "REPLACE_GMAIL_CREDENTIAL",
          "name": "Gmail account (placeholder)"
        }
      }
    },
    {
      "id": "35861aad-97d6-531b-a886-4674bb23da67",
      "name": "Acknowledge Twilio (text)",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        660,
        420
      ],
      "parameters": {
        "respondWith": "text",
        "responseBody": "<Response></Response>",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/xml"
              }
            ]
          }
        }
      }
    },
    {
      "id": "83b4ecc2-556c-5dd2-869e-58108a5f5af2",
      "name": "Read wait (text)",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        880,
        420
      ],
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "={{ $('Config (edit me)').item.json.wait_sheet_id }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Wait",
          "mode": "name"
        },
        "options": {}
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "REPLACE_SHEETS_CREDENTIAL",
          "name": "Google Sheets account (placeholder)"
        }
      },
      "alwaysOutputData": true
    },
    {
      "id": "5cabb0bb-b7e6-5d84-8dc4-ad24fa53d9e9",
      "name": "Owner setting the wait?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1100,
        420
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "8efdabdc-a71c-5333-958b-f199aac065c4",
              "leftValue": "={{ $('Incoming text').item.json.body.From }}",
              "rightValue": "={{ $('Config (edit me)').item.json.owner_cell }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            },
            {
              "id": "f17d3bed-0b7d-51de-97fc-b6e7c5a59ba9",
              "leftValue": "={{ $('Incoming text').item.json.body.Body.trim() }}",
              "rightValue": "WAIT ",
              "operator": {
                "type": "string",
                "operation": "startsWith"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "543f7cb4-0c18-5e76-b2a7-7a9a6fa6f8a7",
      "name": "Save new wait",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1320,
        260
      ],
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "={{ $('Config (edit me)').item.json.wait_sheet_id }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Wait",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "row_key": "current",
            "current_wait": "={{ $('Incoming text').item.json.body.Body.trim().slice(5) }}",
            "updated_at": "={{ $now.toFormat('h:mm a') }}"
          },
          "matchingColumns": [
            "row_key"
          ],
          "schema": [
            {
              "id": "row_key",
              "displayName": "row_key",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "current_wait",
              "displayName": "current_wait",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ]
        },
        "options": {}
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "REPLACE_SHEETS_CREDENTIAL",
          "name": "Google Sheets account (placeholder)"
        }
      }
    },
    {
      "id": "f9442992-3603-5dce-aa7a-f06aa357fd71",
      "name": "Confirm to owner",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1540,
        260
      ],
      "parameters": {
        "from": "={{ $('Config (edit me)').item.json.twilio_number }}",
        "to": "={{ $('Incoming text').item.json.body.From }}",
        "message": "=Got it. Current wait set to: {{ $('Incoming text').item.json.body.Body.trim().slice(5) }}",
        "options": {}
      },
      "credentials": {
        "twilioApi": {
          "id": "REPLACE_TWILIO_CREDENTIAL",
          "name": "Twilio account (placeholder)"
        }
      }
    },
    {
      "id": "f9efd552-f36f-5384-8306-b4c2e0946c16",
      "name": "Asking about the wait?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1320,
        440
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "450c8623-9742-58bd-b83f-18e78bc0d8f7",
              "leftValue": "={{ $('Incoming text').item.json.body.Body }}",
              "rightValue": "wait",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "a557f960-2575-505f-9896-5c9dc75b8a79",
      "name": "Reply with wait time",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1540,
        410
      ],
      "parameters": {
        "from": "={{ $('Config (edit me)').item.json.twilio_number }}",
        "to": "={{ $('Incoming text').item.json.body.From }}",
        "message": "=Hey! Walk-ins welcome at {{ $('Config (edit me)').item.json.business_name }}. Hours: {{ $('Config (edit me)').item.json.hours }}. Current wait: about {{ $('Read wait (text)').first().json.current_wait || 'ask us' }}. Rather book a time? {{ $('Config (edit me)').item.json.booking_link }}",
        "options": {}
      },
      "credentials": {
        "twilioApi": {
          "id": "REPLACE_TWILIO_CREDENTIAL",
          "name": "Twilio account (placeholder)"
        }
      }
    },
    {
      "id": "9469fe54-5953-5d18-a289-297b818d1110",
      "name": "AI writes reply",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.8,
      "position": [
        1540,
        620
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "id"
        },
        "messages": {
          "values": [
            {
              "content": "You are the friendly front desk for a neighborhood barbershop that takes both appointments and walk-ins. Write one short, casual SMS reply (under 300 characters). Always give the booking link for appointments AND mention walk-ins are welcome with today's hours and current wait if provided. Don't quote prices unless they are in the info you were given. Don't promise a specific barber is available.",
              "role": "system"
            },
            {
              "content": "=Business: {{ $('Config (edit me)').item.json.business_name }}\nHours: {{ $('Config (edit me)').item.json.hours }}\nBooking link: {{ $('Config (edit me)').item.json.booking_link }}\nWalk-ins welcome. Current wait: {{ $('Read wait (text)').first().json.current_wait || 'unknown' }}\nCustomer's text: {{ $('Incoming text').item.json.body.Body }}"
            }
          ]
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "REPLACE_OPENAI_CREDENTIAL",
          "name": "OpenAI account (placeholder)"
        }
      }
    },
    {
      "id": "18611720-a598-55a2-a45c-e67d96178182",
      "name": "Text the AI reply",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1760,
        620
      ],
      "parameters": {
        "from": "={{ $('Config (edit me)').item.json.twilio_number }}",
        "to": "={{ $('Incoming text').item.json.body.From }}",
        "message": "={{ $json.message.content }}",
        "options": {}
      },
      "credentials": {
        "twilioApi": {
          "id": "REPLACE_TWILIO_CREDENTIAL",
          "name": "Twilio account (placeholder)"
        }
      }
    },
    {
      "id": "1d04159b-3825-5cc4-97dd-fd93136821c1",
      "name": "Email owner about the text",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1980,
        620
      ],
      "parameters": {
        "sendTo": "={{ $('Config (edit me)').item.json.owner_email }}",
        "subject": "=New text from {{ $('Incoming text').item.json.body.From }}",
        "emailType": "text",
        "message": "=They wrote: {{ $('Incoming text').item.json.body.Body }}\n\nWe auto-replied: {{ $('AI writes reply').item.json.message.content }}",
        "options": {}
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "REPLACE_GMAIL_CREDENTIAL",
          "name": "Gmail account (placeholder)"
        }
      }
    },
    {
      "id": "d64ad68e-643b-5acf-83aa-fa7bcd491023",
      "name": "Setup steps",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -520,
        -120
      ],
      "parameters": {
        "content": "## Setup (about 1 hour)\n1. Open **Config (edit me)** and fill in your business name, booking link, hours, email, cell and Twilio number.\n2. Click each node with a red warning and connect your own **Twilio**, **OpenAI**, **Gmail** and **Google Sheets** credentials.\n3. In Twilio, on your number: Voice > 'A call comes in' > TwiML Bin with:\n`<Response><Dial timeout=\"20\" action=\"YOUR_N8N_URL/webhook/missed-call\">+1YOURCELL</Dial></Response>`\n4. Messaging > 'A message comes in' > Webhook `YOUR_N8N_URL/webhook/incoming-sms` (POST).\n5. Register your number for A2P 10DLC in Twilio before texting customers.\n6. Activate the workflow.\n\n**Walk-ins:** make a Google Sheet with a tab named `Wait`, columns `row_key | current_wait | updated_at`, one row with row_key `current`. Text `WAIT 20 min` from the owner cell to update it.",
        "height": 520,
        "width": 480
      }
    }
  ],
  "connections": {
    "Call ended (from Twilio)": {
      "main": [
        [
          {
            "node": "Config (edit me)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Incoming text": {
      "main": [
        [
          {
            "node": "Config (edit me)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config (edit me)": {
      "main": [
        [
          {
            "node": "Call or text?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call or text?": {
      "main": [
        [
          {
            "node": "Tell Twilio what to say",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Acknowledge Twilio (text)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tell Twilio what to say": {
      "main": [
        [
          {
            "node": "Was the call missed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Was the call missed?": {
      "main": [
        [
          {
            "node": "Read current wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read current wait": {
      "main": [
        [
          {
            "node": "Text the caller",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Text the caller": {
      "main": [
        [
          {
            "node": "Email the owner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Acknowledge Twilio (text)": {
      "main": [
        [
          {
            "node": "Read wait (text)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read wait (text)": {
      "main": [
        [
          {
            "node": "Owner setting the wait?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Owner setting the wait?": {
      "main": [
        [
          {
            "node": "Save new wait",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Asking about the wait?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save new wait": {
      "main": [
        [
          {
            "node": "Confirm to owner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Asking about the wait?": {
      "main": [
        [
          {
            "node": "Reply with wait time",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI writes reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI writes reply": {
      "main": [
        [
          {
            "node": "Text the AI reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Text the AI reply": {
      "main": [
        [
          {
            "node": "Email owner about the text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": false,
    "generatedBy": "Speed-to-Lead Playbooks"
  },
  "tags": []
}