{
  "name": "Tribal Cowboy - Booking Closer",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 * * *"
            }
          ]
        }
      },
      "id": "schedule-trigger-closer",
      "name": "Daily 9am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "url": "https://tribal-cowboy-webhook.onrender.com/voice-inquiries",
        "options": {}
      },
      "id": "fetch-leads",
      "name": "Fetch Voice Leads",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "prompt-var",
              "name": "prompt",
              "value": "=Review these voice inquiries from Tribal Cowboy's ElevenLabs agent. For each lead that needs a follow-up SMS today, return a JSON array only \u2014 no extra text, no markdown, just the raw JSON array.\n\nEach item must have exactly:\n- id: the lead's id field\n- name: lead's first name\n- phone: phone number in E.164 format (e.g. +12145551234)\n- message: the SMS to send (under 160 chars, warm, personalized)\n- category: Hot, Warm, Cold, or Lost\n- action: \"send\" if SMS should be sent today, \"skip\" if Lost or already contacted 3+ times\n\nLeads:\n{{ JSON.stringify($json) }}\n\nBooking URL: https://www.tribalcowboy.com\n\nOnly set action \"send\" if the lead genuinely needs outreach today. Lost leads and over-contacted leads get action \"skip\".",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "set-prompt-closer",
      "name": "Build Prompt",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.prompt }}",
        "messages": {
          "messageValues": [
            {
              "message": "You are the Booking Closer Agent for Tribal Cowboy LLC. Your job is to turn every inquiry into a confirmed, deposited booking.\n\nLead Categories:\n- Hot: inquired within 24hrs, specific date + service\n- Warm: 1-7 days ago, responded but no deposit\n- Cold: 7+ days, no response after 2 touchpoints\n- Lost: explicitly declined or no response after 3+ touchpoints\n\nSMS Sequences (under 160 chars each):\n1. First Contact: 'Hey [Name]! Tribal Cowboy here \u2014 got your inquiry about [service] for [date]. We'd love to help! Book here: [URL]'\n2. 24hr follow-up: 'Hi [Name], following up on your [service] inquiry! Dates go fast \u2014 grab yours: [URL]'\n3. 72hr: 'Hey [Name]! Last check-in from Tribal Cowboy. Still interested? [URL]'\n4. Warm/deposit: 'Hi [Name]! To hold your [date], just need a 25% deposit. Takes 2 min: [URL]'\n\nRules: Personalize every message with name, service, date. Never chase more than 3 times. Mark as skip if Lost or 3+ contacts already made.\n\nIMPORTANT: Return ONLY a valid JSON array. No explanation, no markdown, no extra text. Just raw JSON starting with [ and ending with ]."
            }
          ]
        },
        "batching": {}
      },
      "id": "llm-chain-closer",
      "name": "Booking Closer Agent",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.5,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "model": "claude-sonnet-4-6",
        "options": {
          "maxTokensToSample": 4096
        }
      },
      "id": "claude-model-closer",
      "name": "Anthropic Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        900,
        500
      ]
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nconst raw = items[0].json.text || items[0].json.output || '';\n\nconst cleaned = raw.replace(/```json|```/g, '').trim();\nconst match = cleaned.match(/\\[[\\s\\S]*\\]/);\nif (!match) {\n  return [{ json: { error: 'No JSON array in response', raw } }];\n}\n\ntry {\n  const leads = JSON.parse(match[0]);\n  return leads.map(lead => ({ json: lead }));\n} catch(e) {\n  return [{ json: { error: 'JSON parse failed', raw, message: e.message } }];\n}"
      },
      "id": "parse-leads",
      "name": "Parse Leads",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "filter-send",
              "leftValue": "={{ $json.action }}",
              "rightValue": "send",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "filter-send",
      "name": "Only Send Leads",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1340,
        300
      ]
    },
    {
      "parameters": {
        "operation": "create",
        "from": "={{ $credentials.phoneNumber }}",
        "to": "={{ $json.phone }}",
        "message": "={{ $json.message }}"
      },
      "id": "twilio-send",
      "name": "Send SMS via Twilio",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1560,
        260
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "=https://tribal-cowboy-webhook.onrender.com/voice-inquiry/{{ $json.id }}",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "status",
              "value": "Contacted"
            }
          ]
        },
        "options": {}
      },
      "id": "patch-lead-status",
      "name": "Mark Lead as Contacted",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1780,
        260
      ]
    },
    {
      "parameters": {
        "sendTo": "info@tribalcowboy.com",
        "subject": "=\ud83d\udcf1 Booking Closer Report \u2014 {{ $now.toFormat('MMM d, yyyy') }}",
        "emailType": "text",
        "message": "=SMS sent to {{ $json.name }} ({{ $json.phone }})\nCategory: {{ $json.category }}\nMessage sent: {{ $json.message }}\nLead status updated to: Contacted\n\nTime: {{ $now.toFormat('h:mm a') }}"
      },
      "id": "gmail-sms-confirm",
      "name": "Email SMS Confirmation",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        2000,
        260
      ]
    }
  ],
  "connections": {
    "Daily 9am": {
      "main": [
        [
          {
            "node": "Fetch Voice Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Voice Leads": {
      "main": [
        [
          {
            "node": "Build Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Prompt": {
      "main": [
        [
          {
            "node": "Booking Closer Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Booking Closer Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Booking Closer Agent": {
      "main": [
        [
          {
            "node": "Parse Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Leads": {
      "main": [
        [
          {
            "node": "Only Send Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Only Send Leads": {
      "main": [
        [
          {
            "node": "Send SMS via Twilio",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Send SMS via Twilio": {
      "main": [
        [
          {
            "node": "Mark Lead as Contacted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Lead as Contacted": {
      "main": [
        [
          {
            "node": "Email SMS Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}