{
  "presetId": "generic",
  "presetVersion": "2.1.0",
  "schemaVersion": "0.1",
  "title": "Generic Client",
  "description": "The neutral lead-to-customer fallback build at v2 depth (agency, \"other\", and any unmatched type; clinic / coach / ecommerce / local service now have their own presets). Sales pipeline, core fields, tag system, booking calendar, intake form + landing page, 15 email + 17 SMS send-ready templates, and 10 workflows: Speed to Lead (15 actions, 5 touches in 24 h, then a hand-off), Missed Call Text-Back, Lead Nurture (31 days, 11 touches), Replied - Stop & Route, Win-back (31 days, 5 touches), Appointment Booked - Confirm & Move, Appointment Reminders, No-Show Rescue. Industry-neutral copy that still reads like a person wrote it; the build stage rewrites every template from the brief, plus Quote Follow-up and Review Request (v2.1.0).",
  "default": false,
  "selectors": {
    "businessTypes": [
      "Agency",
      "Other"
    ],
    "aliases": [
      "generic",
      "agency",
      "other"
    ]
  },
  "source": "ghl-command showcase-video Modules 0-7 + a proven med-spa build; v2 depth per the owner review of 2026-08-26.",
  "conventions": {
    "triggerTokens": "Use ONLY the executor's native trigger types so triggers auto-build: contact_tag (tagRef), form_submission (formRef), appointment (appointmentStatus: confirmed|noshow|...; calendarRef optional), customer_reply, pipeline_stage_updated (pipelineRef+stageRef), call_status (callStatuses + callDirection; the missed-call text-back), inbound_webhook, payment_received. Never tag_added / form_submitted / appointment_status / appointment_booked / contact_replied.",
    "handoffTag": "Sequences hand off with add_contact_tag + a contact_tag trigger (nurture-start, winback-start), NOT add_to_workflow. Both halves of the tag hand-off are live-proven action shapes (the add-tag node and the tag trigger are captured from working GHL UI-built workflows in templates/action-schemas.json); add_to_workflow has no captured native shape in action-schemas.json and has not been proven at runtime, so a preset may not use it. Each sequence removes its own trigger tag as its first action so a later hand-off can fire it again.",
    "nurtureSpan": "Lead Nurture waits sum to 31 days (owner rule: nothing under 30 days). Win-back waits sum to 31 days. Speed to Lead must end with the nurture-start hand-off tag. The validator rejects a /nurture/i workflow under 30 days of waits and a /speed/i workflow without a hand-off.",
    "staff": "Every internal_notification, task_notification and assign_user carries userRef. In the skeleton the ref is the ROLE PLACEHOLDER user.owner; the fill step maps it per step from brief.team (notifyName for notifications, callsName for tasks and assignment, each calendar's staffNames for teamMemberRefs; \"the owner\" = the first admin). No staff in the brief → userRef: \"user.__pending__\" on every such step, the step is KEPT, the build reports it as waiting, and handoff.add_staff holds that workflow DRAFT. Never write a literal user id (the legacy `to` / `assignedTo`).",
    "publishDefault": "Workflows build DRAFT. The skill PROMPTS the operator (publish now or leave DRAFT for review?) and only passes publishWorkflows:true on an explicit yes. Workflows gated by an unmet handoff never auto-publish.",
    "a2pGating": "handoff.a2p.blocks MUST list each SMS-bearing WORKFLOW ref (not just sms.* assets); only an explicit workflow.* ref keeps a workflow DRAFT.",
    "copy": "All copy lives in templates.* (email_template.* / sms_template.*) and is COMPLETE. The build stage rewrites every template from the real brief per references/copy-guide.md (five tests: Jab, Value equation, Says-who, Lock-screen, Thumb), in the tone of brief.voice.threeWords, with brief.voice.signatureLine verbatim in the instant email and text, keeps merge fields and the single CTA, and writes the result to the template AND the matching email/sms asset body. An email/sms asset with only copyDirection and no body reports needsContent and will not build.",
    "fortyCap": "Max 40 actions per workflow (a find_opportunity branch counts head + 2 transitions + children). The longest workflow here is Lead Nurture at 28 actions, so no split is needed; if a rewrite adds touches past 40, split into \"(days 1-14)\" and \"(days 15-30)\" with a hand-off tag between them."
  },
  "skeleton": {
    "users": {
      "fillFrom": "team.staff",
      "transform": "userList",
      "default": [],
      "_note": "One plan user per brief.team.staff[] entry: ref user.<slug of name>, firstName/lastName split from name, email verbatim, role admin for the owner / whoever runs the account, else user, phone from mobile. In this skeleton \"user.owner\" is a ROLE PLACEHOLDER, never a real user: the fill step resolves it per step — internal_notification → the user named by brief.team.notifyName; task_notification and assign_user → brief.team.callsName; calendars[].teamMemberRefs → that calendar's staffNames; \"the owner\" / \"me\" → the first admin. If the brief lists nobody, every userRef becomes the sentinel \"user.__pending__\" and the step is KEPT (the build reports it as waiting for a staff member; handoff.add_staff holds that workflow DRAFT)."
    },
    "pipelines": [
      {
        "ref": "pipeline.main",
        "name": "{{business.name}} Pipeline || Sales Pipeline",
        "stages": {
          "fillFrom": "goal.salesStages",
          "transform": "stageList",
          "default": [
            {
              "ref": "stage.new_lead",
              "name": "New Lead"
            },
            {
              "ref": "stage.contacted",
              "name": "Contacted"
            },
            {
              "ref": "stage.qualified",
              "name": "Qualified"
            },
            {
              "ref": "stage.appointment_booked",
              "name": "Appointment Booked",
              "conditionalOn": "goal.bookingNeeded == true"
            },
            {
              "ref": "stage.proposal_sent",
              "name": "Proposal / Quote Sent"
            },
            {
              "ref": "stage.won",
              "name": "Won"
            },
            {
              "ref": "stage.repeat",
              "name": "Repeat / Retention"
            },
            {
              "ref": "stage.lost",
              "name": "Lost"
            }
          ]
        }
      }
    ],
    "customFields": [
      {
        "ref": "field.lead_source",
        "name": "Lead Source",
        "dataType": "SINGLE_OPTIONS",
        "model": "contact",
        "options": [
          "Website",
          "Instagram",
          "Facebook",
          "Google",
          "Referral",
          "Phone",
          "Other"
        ]
      },
      {
        "ref": "field.interest",
        "name": "What They Need",
        "dataType": "SINGLE_OPTIONS",
        "model": "contact",
        "options": [
          "Pricing / a quote",
          "Book a time",
          "A question first",
          "Other"
        ],
        "_optionsNote": "The skill derives service-specific options from offer.summary at fill time and mirrors them with interest-* tags."
      },
      {
        "ref": "field.top_concern",
        "name": "Top Concern",
        "dataType": "TEXT",
        "model": "contact",
        "_note": "Filled by staff from the speed-to-lead reply."
      },
      {
        "ref": "field.appt_date",
        "name": "Appointment Date",
        "dataType": "DATE",
        "model": "contact",
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "field.deal_sold",
        "name": "Deal Sold",
        "dataType": "TEXT",
        "model": "contact"
      },
      {
        "ref": "field.ltv",
        "name": "Estimated Lifetime Value",
        "dataType": "MONETORY",
        "model": "contact"
      }
    ],
    "tags": [
      {
        "ref": "tag.source_website",
        "name": "source-website"
      },
      {
        "ref": "tag.source_instagram",
        "name": "source-instagram"
      },
      {
        "ref": "tag.source_facebook",
        "name": "source-facebook"
      },
      {
        "ref": "tag.source_google",
        "name": "source-google"
      },
      {
        "ref": "tag.source_referral",
        "name": "source-referral"
      },
      {
        "ref": "tag.source_phone",
        "name": "source-phone"
      },
      {
        "ref": "tag.source_other",
        "name": "source-other"
      },
      {
        "ref": "tag.lc_new_lead",
        "name": "lifecycle-new-lead"
      },
      {
        "ref": "tag.lc_contacted",
        "name": "lifecycle-contacted"
      },
      {
        "ref": "tag.lc_nurturing",
        "name": "lifecycle-nurturing"
      },
      {
        "ref": "tag.lc_booked",
        "name": "lifecycle-booked",
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "tag.lc_qualified",
        "name": "lifecycle-qualified"
      },
      {
        "ref": "tag.lc_won",
        "name": "lifecycle-won"
      },
      {
        "ref": "tag.lc_repeat",
        "name": "lifecycle-repeat"
      },
      {
        "ref": "tag.lc_lapsed",
        "name": "lifecycle-lapsed"
      },
      {
        "ref": "tag.lc_lost",
        "name": "lifecycle-lost"
      },
      {
        "ref": "tag.nurture_start",
        "name": "nurture-start"
      },
      {
        "ref": "tag.winback_start",
        "name": "winback-start"
      },
      {
        "ref": "tag.missed_call",
        "name": "missed-call",
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "tag.no_show",
        "name": "no-show",
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "tag.review_ask",
        "name": "review-ask"
      },
      {
        "ref": "tag.review_asked",
        "name": "review-asked"
      },
      {
        "ref": "tag.quote_sent",
        "name": "quote-sent"
      },
      {
        "ref": "tag.quote_open",
        "name": "quote-open"
      },
      {
        "ref": "tag.quote_no_reply",
        "name": "quote-no-reply"
      }
    ],
    "_tagNote": "The skill derives interest-<x> tags from offer.summary at fill time and adds them here, mirroring the What They Need field options. Not pre-declared because they are business-specific.",
    "customValues": [
      {
        "ref": "cv.business_name",
        "name": "business_name",
        "value": "{{business.name}}"
      },
      {
        "ref": "cv.business_phone",
        "name": "business_phone",
        "value": "",
        "filledBy": "handoff.business_details",
        "_fill": "the GHL number once one exists (handoff.phone_number), else blank until the operator fills it"
      },
      {
        "ref": "cv.owner_first_name",
        "name": "owner_first_name",
        "value": "",
        "filledBy": "handoff.business_details",
        "_fill": "first name of the user resolved for team.notifyName (the person every message is signed by)"
      },
      {
        "ref": "cv.booking_link",
        "name": "booking_link",
        "value": "",
        "filledBy": "handoff.calendar_oauth",
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "cv.review_link",
        "name": "review_link",
        "value": "",
        "filledBy": "handoff.review_link"
      }
    ],
    "calendars": [
      {
        "ref": "calendar.consult",
        "conditionalOn": "goal.bookingNeeded == true",
        "name": "{{business.name}} Consultation || Consultation",
        "calendarType": "round_robin",
        "_slotDuration": "Carry the appointment length from the brief (brief.calendars[].durationMinutes, or the words in the calendar answer: \"15 minutes\" → 15) onto slotDuration (minutes, slotDurationUnit \"mins\"). This preset value applies ONLY when the brief gives no length; without any slotDuration GoHighLevel builds 30-minute slots (finding 25).",
        "slotDuration": 30,
        "slotDurationUnit": "mins",
        "teamMemberRefs": [
          "user.owner"
        ],
        "openHours": [
          {
            "daysOfTheWeek": [
              1,
              2,
              3,
              4,
              5
            ],
            "hours": [
              {
                "openHour": 9,
                "openMinute": 0,
                "closeHour": 17,
                "closeMinute": 0
              }
            ]
          }
        ],
        "availabilityType": 0,
        "slotBuffer": 10,
        "requiresStaff": true,
        "notes": "Default Mon-Fri 9-5; operator edits after build. teamMemberRefs points at the plan users who take appointments; with no staff in the brief it is emptied and handoff.assign_calendar_staff applies."
      }
    ],
    "_calendarsNote": "One plan calendar per brief.calendars[] entry. The first booking calendar in the brief maps onto this ref (its name, type one_on_one→event / round_robin→round_robin / class→class_booking, and teamMemberRefs from staffNames replace the defaults); every further entry is appended as calendar.<slug> with its own teamMemberRefs. The appointment workflows attach to this first calendar. No calendars in the brief and goal.bookingNeeded true → keep this default and note the assumption.",
    "forms": [
      {
        "ref": "form.intake",
        "name": "{{business.name}} Inquiry || New Inquiry",
        "fields": [
          {
            "type": "standard",
            "key": "first_name",
            "required": true
          },
          {
            "type": "standard",
            "key": "last_name",
            "required": false
          },
          {
            "type": "standard",
            "key": "email",
            "required": true
          },
          {
            "type": "standard",
            "key": "phone",
            "required": true
          },
          {
            "type": "custom",
            "fieldRef": "field.interest",
            "required": false
          }
        ]
      }
    ],
    "templates": {
      "emails": [
        {
          "ref": "email_template.stl_email_1",
          "name": "Speed to Lead - Instant Email",
          "subject": "Got it, {{contact.first_name}}. Here's what happens next",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Thanks for reaching out to {{custom_values.business_name}}. I'm {{custom_values.owner_first_name}}, and I see every inquiry that comes in.</p><p style=\"margin:0 0 14px;\">Here's what happens next: in the next few minutes you'll get a text from this number. Reply with one line about what you're trying to sort out, and I'll tell you straight whether we're the right fit, and what it would take.</p><p style=\"margin:0 0 14px;\">If you'd rather just talk, grab {{offer.leadMagnet || a quick call}}:</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Pick a time that suits me</a></p><p style=\"margin:0 0 14px;\">No pitch, no pressure. You'll leave the call knowing exactly what your options are.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.stl_email_2",
          "name": "Speed to Lead - 3 Hour Email",
          "subject": "The three questions we ask first",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Before anyone at {{custom_values.business_name}} recommends anything, we ask three questions:</p><ul style=\"margin:0 0 14px 20px;padding:0;\"><li style=\"margin:0 0 6px;\">What does \"fixed\" look like to you, in one sentence?</li><li style=\"margin:0 0 6px;\">What have you already tried, and what happened?</li><li style=\"margin:0 0 6px;\">What's the cost of leaving it as it is for another six months?</li></ul><p style=\"margin:0 0 14px;\">Your answers decide what we'd suggest and what we'd tell you not to bother with. That's the whole point of the first conversation.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Book the conversation</a></p><p style=\"margin:0 0 14px;\">Or reply to this email with your answer to the first question. I read every reply.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.n_email_1",
          "name": "Nurture 1 - The Mistake Most People Make",
          "subject": "The mistake most people make with {{audience.painPoints[0] || the problem you reached out about}}",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">When people first contact us about {{audience.painPoints[0] || the problem you reached out about}}, most have already made the same mistake: they've waited until it was urgent, then picked whoever answered the phone first.</p><p style=\"margin:0 0 14px;\">Urgent decisions are expensive decisions. The better first move is boring: get the problem described properly, get two or three options with real prices, and pick the one that solves the actual problem instead of the loudest symptom.</p><p style=\"margin:0 0 14px;\">That's what our first conversation is for. It's short, it's free, and you can take what you learn anywhere you like.</p><p style=\"margin:0 0 14px;\">When you're ready: <a href=\"{{custom_values.booking_link}}\" style=\"color:#1a56db;text-decoration:underline;\">pick a time</a>.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.n_email_2",
          "name": "Nurture 2 - How Working With Us Goes",
          "subject": "How working with us actually goes",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">People hesitate because they don't know what happens after they say yes. So here it is:</p><ul style=\"margin:0 0 14px 20px;padding:0;\"><li style=\"margin:0 0 6px;\">Step 1: a short conversation. You describe the problem; we ask the three questions; you get honest options.</li><li style=\"margin:0 0 6px;\">Step 2: a written proposal with what we'd do, what it costs, and what you should expect by when. You take it away; nobody chases you the same day.</li><li style=\"margin:0 0 6px;\">Step 3: we do the work, you get updates you didn't have to ask for, and we don't call it done until you do.</li></ul><p style=\"margin:0 0 14px;\">The objection we hear most is {{audience.objections[0] || cost}}. That's why step 2 is in writing with options, so you choose the scope, not us.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Start with step 1</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.n_email_3",
          "name": "Nurture 3 - Why We Do It This Way",
          "subject": "Why we do it this way",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">The best thing a client can say about {{custom_values.business_name}} is \"there were no surprises.\" Not the most exciting compliment. It's the one that gets us referred.</p><p style=\"margin:0 0 14px;\">It comes from a rule: everything in writing before it happens, and you hear about a problem from us before you notice it yourself. Slower to set up than a handshake. Far cheaper by the end.</p><p style=\"margin:0 0 14px;\">If you want to see what that looks like for your situation, that's what the first conversation is for.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">See my options</a></p><p style=\"margin:0 0 14px;\">Have a question first? Reply to this email. I'll answer it myself.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.n_email_4",
          "name": "Nurture 4 - About the Cost",
          "subject": "About the cost",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Let's talk about the thing most people are too polite to ask: what does it cost?</p><p style=\"margin:0 0 14px;\">{{offer.summary || What we do}} is priced by scope, and the scope is yours to choose. The written proposal shows options side by side, with the price of each, before anything starts. There is never a number on the invoice you didn't see first.</p><p style=\"margin:0 0 14px;\">One honest warning: the cheapest quote is rarely the cheapest job. If a price looks too good, ask what's been left out. We'll tell you what's in ours line by line.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Get my written options</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.n_email_5",
          "name": "Nurture 5 - What Waiting Costs",
          "subject": "What waiting actually costs",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">There's a comfortable idea that {{audience.painPoints[0] || the problem you reached out about}} can wait until a better month. Sometimes true. Usually not.</p><p style=\"margin:0 0 14px;\">Problems like this rarely stay the same size. They compound quietly, and then one day they're urgent, and urgent always costs more than planned: less choice, less time to compare, more money.</p><p style=\"margin:0 0 14px;\">You don't have to do anything today. A conversation now just keeps the cheap options on the table.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Keep my options open</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.n_email_6",
          "name": "Nurture 6 - Everything in One Place",
          "subject": "Everything you need to decide, in one place",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">If you're still weighing it up, here is everything in one place:</p><ul style=\"margin:0 0 14px 20px;padding:0;\"><li style=\"margin:0 0 6px;\">What: {{offer.leadMagnet || a quick call}} with {{custom_values.business_name}}, and written options you keep.</li><li style=\"margin:0 0 6px;\">Where: {{business.location || we come to you or meet online}}.</li><li style=\"margin:0 0 6px;\">Cost of the first step: nothing. Cost of the work: shown per option, in writing, before anything starts.</li><li style=\"margin:0 0 6px;\">Our rule: no surprises. You hear about problems from us first.</li><li style=\"margin:0 0 6px;\">Book, cancel or move your time any time: <a href=\"{{custom_values.booking_link}}\" style=\"color:#1a56db;text-decoration:underline;\">your booking link</a>.</li></ul><p style=\"margin:0 0 14px;\">If the answer is \"not now\", that's fine. Reply with the word later and I'll stop the emails and check in next quarter.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Book the conversation</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.w_email_1",
          "name": "Win-back 1 - One Question",
          "subject": "One question, {{contact.first_name}}",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">A while back you reached out to {{custom_values.business_name}} about {{audience.painPoints[0] || the problem you reached out about}}, and then things went quiet. That's normal; it's what happens when something isn't urgent yet.</p><p style=\"margin:0 0 14px;\">One question, and an honest answer is all I need: what stopped you? Timing, price, trust, or something we said?</p><p style=\"margin:0 0 14px;\">Reply with a word or two. If it's something we can fix, I'll fix it. If it's not the right time, I'll leave you alone until it is.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.w_email_2",
          "name": "Win-back 2 - What Changed",
          "subject": "What's changed since you last looked",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Since you first reached out, a couple of things have changed at {{custom_values.business_name}}: more availability on the calendar, and written options that now include a smaller first step for people who want to start carefully.</p><p style=\"margin:0 0 14px;\">What hasn't changed: the first conversation is still free, still short, and still ends with options you take away rather than a decision on the spot.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">See the calendar</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.w_email_3",
          "name": "Win-back 3 - The Door Stays Open",
          "subject": "The door stays open",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">This is the last automatic email you'll get from me. I'd rather you hear from a person when the time is right than from a sequence.</p><p style=\"margin:0 0 14px;\">Your first conversation doesn't expire. When you're ready, the link below works, and so does replying to this email.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Book when you're ready</a></p><p style=\"margin:0 0 14px;\">Thanks for considering us. And whatever you do about {{audience.painPoints[0] || the problem you reached out about}}, get it in writing first.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.appt_confirm_email",
          "name": "Appointment Confirmed",
          "subject": "Confirmed, {{contact.first_name}}: your appointment details",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Your appointment with {{custom_values.business_name}} is confirmed for {{appointment.start_time}}.</p><p style=\"margin:0 0 14px;\">What to have ready: a one-line description of the problem and anything you've already tried. That's it.</p><p style=\"margin:0 0 14px;\">What you'll leave with: honest options and, if you want it, a written proposal within a day or two.</p><p style=\"margin:0 0 14px;\">Need to move it? Use your booking link: <a href=\"{{custom_values.booking_link}}\" style=\"color:#1a56db;text-decoration:underline;\">reschedule</a>, or reply to this email.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.appt_prep_email",
          "name": "Appointment Prep (day before)",
          "subject": "Tomorrow: 3 things that make it more useful",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">See you tomorrow at {{appointment.start_time}}. Three small things that make the time more useful:</p><ul style=\"margin:0 0 14px 20px;padding:0;\"><li style=\"margin:0 0 6px;\">Write down what \"fixed\" looks like to you, in one sentence.</li><li style=\"margin:0 0 6px;\">Have any quotes, photos or documents you already have to hand.</li><li style=\"margin:0 0 6px;\">Decide the one question you most want answered. We'll start there.</li></ul><p style=\"margin:0 0 14px;\">Running late or need to move it? Reply to this email or call {{custom_values.business_phone}}.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.ns_email_1",
          "name": "No-Show 1 - We Missed You",
          "subject": "We missed you, {{contact.first_name}} (no guilt)",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">We had you down for today and it didn't work out. Life happens; nobody here is bothered.</p><p style=\"margin:0 0 14px;\">Your time is still yours. Pick a new one whenever it suits, and if something put you off, reply and tell me. I'd rather know.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Rebook my time</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.ns_email_2",
          "name": "No-Show 2 - Still Want This?",
          "subject": "Still want to do this?",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Quick and honest: if the timing is wrong, say so and I'll check back in a few months. If it's still something you want sorted, the calendar is open.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.booking_link}}\" style=\"display:inline-block;background:#1a56db;color:#ffffff;padding:12px 20px;border-radius:6px;text-decoration:none;font-weight:600;\">Pick a new time</a></p><p style=\"margin:0 0 14px;\">Either way, thanks for considering {{custom_values.business_name}}.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.r_email_1",
          "name": "Review Request - Email",
          "subject": "A minute of your time, {{contact.first_name}}?",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">Thank you for choosing {{custom_values.business_name}}. I hope everything went the way you wanted; if it did not, reply to this and I will make it right before anything else.</p><p style=\"margin:0 0 14px;\">If it did, would you leave us a short Google review? A line or two about what we did and how it went is all it takes, and it is genuinely how the next person decides to call.</p><p style=\"margin:0 0 14px;\"><a href=\"{{custom_values.review_link}}\">Leave a review here</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.q_email_1",
          "name": "Quote Follow-up - Email 1",
          "subject": "Your quote from {{custom_values.business_name}}",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">A couple of days ago we sent over the quote for the work you asked about. I wanted to check it landed and that it made sense.</p><p style=\"margin:0 0 14px;\">Two things people usually ask at this point: what is included and what happens if something unexpected turns up. If either is on your mind, reply and I will answer plainly.</p><p style=\"margin:0 0 14px;\">If you are comparing options, that is fine too. Tell me what you are weighing and I will tell you honestly where we stand.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        },
        {
          "ref": "email_template.q_email_2",
          "name": "Quote Follow-up - Email 2",
          "subject": "Last note on the quote, {{contact.first_name}}",
          "html": "<div style=\"font-family:Arial,Helvetica,sans-serif;font-size:16px;line-height:1.5;color:#1f2937;max-width:600px;\"><p style=\"margin:0 0 14px;\">Hi {{contact.first_name}},</p><p style=\"margin:0 0 14px;\">This is the last note from me on the quote for the work you asked about. I would rather ask once more than assume.</p><p style=\"margin:0 0 14px;\">If the timing is off, tell me when would suit and I will hold the price. If it is a no, a one-word reply is welcome and I will stop here.</p><p style=\"margin:0 0 14px;\">Either way, thank you for considering {{custom_values.business_name}}.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
        }
      ],
      "sms": [
        {
          "ref": "sms_template.stl_sms_1",
          "name": "Speed to Lead - Instant Text",
          "body": "Hi {{contact.first_name}}, it's {{custom_values.owner_first_name}} at {{custom_values.business_name}}. Got your inquiry. In one line, what are you trying to sort out? Reply STOP to opt out."
        },
        {
          "ref": "sms_template.stl_sms_2",
          "name": "Speed to Lead - 20 Minute Text",
          "body": "{{contact.first_name}}, I can hold a 30-min slot for you this week. Mornings or afternoons? Or grab one here: {{custom_values.booking_link}}"
        },
        {
          "ref": "sms_template.stl_sms_3",
          "name": "Speed to Lead - Next Day Text",
          "body": "Hi {{contact.first_name}}, {{custom_values.owner_first_name}} again. Not chasing, I just don't want your inquiry to fall through the cracks. Still want to find a time, or is it a \"not now\"?"
        },
        {
          "ref": "sms_template.mc_sms_1",
          "name": "Missed Call - Instant Text-Back",
          "body": "Hi, it's {{custom_values.business_name}}. Sorry we missed your call. How can we help? Reply here and a real person will answer. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.mc_sms_2",
          "name": "Missed Call - 1 Hour Text",
          "body": "Still need us? Reply with a good time to call you back, or book directly: {{custom_values.booking_link}}. {{custom_values.business_name}}, {{custom_values.business_phone}}"
        },
        {
          "ref": "sms_template.n_sms_1",
          "name": "Nurture Text 1 - One Word",
          "body": "{{contact.first_name}}, quick one from {{custom_values.owner_first_name}} at {{custom_values.business_name}}: what matters most to you here, speed, price, or getting it right first time? One word is enough. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.n_sms_2",
          "name": "Nurture Text 2 - Free Tip",
          "body": "Tip from {{custom_values.business_name}}: before you hire anyone for this, ask three things. What exactly is included? What happens if it takes longer? Who do I call if something goes wrong? Want the rest of the list? Reply YES."
        },
        {
          "ref": "sms_template.n_sms_3",
          "name": "Nurture Text 3 - Midpoint",
          "body": "{{contact.first_name}}, it's {{custom_values.owner_first_name}}. Still thinking about {{audience.painPoints[0] || the problem you reached out about}}? I have a couple of openings this week. Want one, or should I check back next month?"
        },
        {
          "ref": "sms_template.n_sms_4",
          "name": "Nurture Text 4 - Any Question",
          "body": "Hi {{contact.first_name}}, {{custom_values.owner_first_name}} here. No pitch, just checking: did you ever get your question answered? If not, ask it here and I'll reply personally."
        },
        {
          "ref": "sms_template.n_sms_5",
          "name": "Nurture Text 5 - Last Direct Ask",
          "body": "{{contact.first_name}}, last one from me at {{custom_values.business_name}}. If you want this sorted this month, reply YES and I'll send two times. If not, no hard feelings. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.w_sms_1",
          "name": "Win-back Text 1",
          "body": "Hi {{contact.first_name}}, it's {{custom_values.owner_first_name}} at {{custom_values.business_name}}. Is this still on your list this quarter, or should I close your file for now? Reply STOP to opt out."
        },
        {
          "ref": "sms_template.w_sms_2",
          "name": "Win-back Text 2",
          "body": "{{contact.first_name}}, two openings came up this week at {{custom_values.business_name}}. Want one for a quick conversation? Reply YES and I'll hold it."
        },
        {
          "ref": "sms_template.appt_confirm_sms",
          "name": "Appointment Confirmed Text",
          "body": "{{contact.first_name}}, you're confirmed with {{custom_values.business_name}} for {{appointment.start_time}}. Need to change it? Reply here. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.appt_24h_sms",
          "name": "Appointment Reminder - 24 Hours",
          "body": "Reminder: your appointment with {{custom_values.business_name}} is tomorrow at {{appointment.start_time}}. Reply C to confirm or R to reschedule."
        },
        {
          "ref": "sms_template.appt_2h_sms",
          "name": "Appointment Reminder - 2 Hours",
          "body": "See you in about 2 hours, {{contact.first_name}}. {{custom_values.business_name}}, {{appointment.start_time}}. Reply here if you're running late."
        },
        {
          "ref": "sms_template.ns_sms_1",
          "name": "No-Show Text 1",
          "body": "Hi {{contact.first_name}}, we missed you today at {{custom_values.business_name}}. No problem at all. Want me to find you a new time this week? Reply YES. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.ns_sms_2",
          "name": "No-Show Text 2",
          "body": "{{contact.first_name}}, {{custom_values.owner_first_name}} here. I kept a couple of times open for you this week. Want one? Reply with a day that works."
        },
        {
          "ref": "sms_template.r_sms_1",
          "name": "Review Request - Text 1",
          "body": "Hi {{contact.first_name}}, it's {{custom_values.owner_first_name}} at {{custom_values.business_name}}. Thank you for choosing us. If we did right by you, a quick Google review helps more than you'd think: {{custom_values.review_link}} Reply STOP to opt out."
        },
        {
          "ref": "sms_template.r_sms_2",
          "name": "Review Request - Text 2",
          "body": "Hi {{contact.first_name}}, last nudge from {{custom_values.owner_first_name}}: a one-line Google review takes about a minute and it's how the next person finds us. {{custom_values.review_link}} Thank you either way. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.q_sms_1",
          "name": "Quote Follow-up - Text 1",
          "body": "Hi {{contact.first_name}}, it's {{custom_values.owner_first_name}} at {{custom_values.business_name}}. Did the quote come through okay? If anything in it needs explaining, reply here and I'll walk you through it. Reply STOP to opt out."
        },
        {
          "ref": "sms_template.q_sms_2",
          "name": "Quote Follow-up - Text 2",
          "body": "Hi {{contact.first_name}}, {{custom_values.owner_first_name}} again. No pressure on the quote; I just don't want it to sit if you had a question. Is timing, price, or something else the sticking point? Reply STOP to opt out."
        }
      ]
    },
    "_templatesNote": "Every message is a send-ready template (emails: subject + html; sms: body) written to references/copy-guide.md from this preset's placeholder brief fields. The build stage REWRITES each one from the real brief (offer, audience pain points and objections, price points, lead magnet, follow-up style, voice.threeWords for tone, voice.signatureLine verbatim in the first email and text) keeping the cadence, the single CTA and the merge fields, then writes the result to BOTH the template and the matching email/sms asset body. Never ship an outline-only body. {{contact.*}}, {{custom_values.*}} and {{appointment.*}} are GHL merge fields and pass through the fill untouched; {{offer.*}} / {{audience.*}} / {{business.*}} are preset tokens filled from the brief.",
    "emails": [
      {
        "ref": "email.stl_email_1",
        "name": "Speed to Lead - Instant Email",
        "subject": "Got it, {{contact.first_name}}. Here's what happens next",
        "templateRef": "email_template.stl_email_1",
        "copyDirection": "Instant. Who I am, what they asked for, the next few minutes (a text is coming), the one-question ask, the booking CTA, the no-pressure promise. Tone: brief.voice.threeWords. If brief.voice.signatureLine exists, insert it verbatim as its own paragraph right after the greeting.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.owner_first_name",
          "custom_values.booking_link",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.stl_email_2",
        "name": "Speed to Lead - 3 Hour Email",
        "subject": "The three questions we ask first",
        "templateRef": "email_template.stl_email_2",
        "copyDirection": "Second touch, 3 hours in. The three diagnostic questions we ask every new client, why they matter, CTA to book, reply invitation.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.n_email_1",
        "name": "Nurture 1 - The Mistake Most People Make",
        "subject": "The mistake most people make with {{audience.painPoints[0] || the problem you reached out about}}",
        "templateRef": "email_template.n_email_1",
        "copyDirection": "Day 1 of nurture. Lead with the top pain point in their words, name the common mistake (waiting, or buying on price alone), teach the better first move. Give, do not pitch.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.n_email_2",
        "name": "Nurture 2 - How Working With Us Goes",
        "subject": "How working with us actually goes",
        "templateRef": "email_template.n_email_2",
        "copyDirection": "Day 5. Remove the unknown: the three steps from first call to done, then name and answer the top objection (audience.objections[0]). One CTA.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.n_email_3",
        "name": "Nurture 3 - Why We Do It This Way",
        "subject": "Why we do it this way",
        "templateRef": "email_template.n_email_3",
        "copyDirection": "Day 10. The method as proof: written scope, no surprises, updates unasked. Client results ONLY if the brief supplies them; otherwise the method is the proof. CTA + reply invite.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.n_email_4",
        "name": "Nurture 4 - About the Cost",
        "subject": "About the cost",
        "templateRef": "email_template.n_email_4",
        "copyDirection": "Day 14. Handle cost head-on: how pricing works (from offer.pricePoints if present), written before anything happens, options at different scopes, the cheapest quote is rarely the cheapest job. No numbers unless the brief has them.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.n_email_5",
        "name": "Nurture 5 - What Waiting Costs",
        "subject": "What waiting actually costs",
        "templateRef": "email_template.n_email_5",
        "copyDirection": "Day 20. Cost of inaction without fear-mongering: the problem compounds, urgent costs more than planned, a conversation now keeps the cheap options open. Soft CTA.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.n_email_6",
        "name": "Nurture 6 - Everything in One Place",
        "subject": "Everything you need to decide, in one place",
        "templateRef": "email_template.n_email_6",
        "copyDirection": "Day 27. The decision sheet: what, where, what the first step costs, how pricing works, our rule, how to book or move. Offer the \"later\" out. One CTA.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.w_email_1",
        "name": "Win-back 1 - One Question",
        "subject": "One question, {{contact.first_name}}",
        "templateRef": "email_template.w_email_1",
        "copyDirection": "Win-back day 0. Acknowledge the gap without guilt; ask what stopped them; promise to fix it or leave them alone. A reply is the CTA.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.w_email_2",
        "name": "Win-back 2 - What Changed",
        "subject": "What's changed since you last looked",
        "templateRef": "email_template.w_email_2",
        "copyDirection": "Win-back day 14. One real reason to look again from the brief (new availability, a new option, a seasonal fit), then what has not changed. One CTA.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.w_email_3",
        "name": "Win-back 3 - The Door Stays Open",
        "subject": "The door stays open",
        "templateRef": "email_template.w_email_3",
        "copyDirection": "Win-back day 30, the last automatic message. Say so plainly, leave the offer open with no expiry, one CTA, one useful parting tip.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.appt_confirm_email",
        "name": "Appointment Confirmed",
        "subject": "Confirmed, {{contact.first_name}}: your appointment details",
        "templateRef": "email_template.appt_confirm_email",
        "copyDirection": "On booking. Date/time via {{appointment.start_time}}, what to have ready, what they leave with, how to move it.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "appointment.start_time",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.appt_prep_email",
        "name": "Appointment Prep (day before)",
        "subject": "Tomorrow: 3 things that make it more useful",
        "templateRef": "email_template.appt_prep_email",
        "copyDirection": "Day before. Three concrete prep items, the time, how to reach us if late.",
        "mergeTags": [
          "contact.first_name",
          "appointment.start_time",
          "custom_values.business_phone",
          "custom_values.owner_first_name",
          "custom_values.business_name"
        ]
      },
      {
        "ref": "email.ns_email_1",
        "name": "No-Show 1 - We Missed You",
        "subject": "We missed you, {{contact.first_name}} (no guilt)",
        "templateRef": "email_template.ns_email_1",
        "copyDirection": "Same day. Zero guilt, the slot is still theirs, rebook CTA, invite the honest reason.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.ns_email_2",
        "name": "No-Show 2 - Still Want This?",
        "subject": "Still want to do this?",
        "templateRef": "email_template.ns_email_2",
        "copyDirection": "Day 4 after the no-show. Honest binary: wrong timing or still want it. One CTA, gracious close.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link",
          "custom_values.business_name",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.r_email_1",
        "name": "Review Request - Email",
        "subject": "A minute of your time, {{contact.first_name}}?",
        "templateRef": "email_template.r_email_1",
        "copyDirection": "Three days after the tag. Thank them, invite the complaint first (reply and I will fix it), then the ask with the link. Tone: brief.voice.threeWords.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.review_link",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.q_email_1",
        "name": "Quote Follow-up - Email 1",
        "subject": "Your quote from {{custom_values.business_name}}",
        "templateRef": "email_template.q_email_1",
        "copyDirection": "Day three. Check it landed, answer the two usual questions before they are asked, welcome comparison. Tone: brief.voice.threeWords.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      },
      {
        "ref": "email.q_email_2",
        "name": "Quote Follow-up - Email 2",
        "subject": "Last note on the quote, {{contact.first_name}}",
        "templateRef": "email_template.q_email_2",
        "copyDirection": "Day ten, the last one. Say it is the last, offer to hold the price for a better time, make a no easy.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "custom_values.owner_first_name",
          "custom_values.business_phone"
        ]
      }
    ],
    "sms": [
      {
        "ref": "sms.stl_sms_1",
        "name": "Speed to Lead - Instant Text",
        "templateRef": "sms_template.stl_sms_1",
        "copyDirection": "Instant. Name + business, acknowledge, the one-line ask, STOP line. No link. If brief.voice.signatureLine is short enough, use it verbatim as the second sentence.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.stl_sms_2",
        "name": "Speed to Lead - 20 Minute Text",
        "templateRef": "sms_template.stl_sms_2",
        "copyDirection": "20 minutes in. Offer to hold a time, binary question, booking link.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.booking_link"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.stl_sms_3",
        "name": "Speed to Lead - Next Day Text",
        "templateRef": "sms_template.stl_sms_3",
        "copyDirection": "Day 1. Not chasing; binary: find a time or \"not now\". No link.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.mc_sms_1",
        "name": "Missed Call - Instant Text-Back",
        "templateRef": "sms_template.mc_sms_1",
        "copyDirection": "Seconds after a missed inbound call. Apologize, ask how to help, promise a real person, STOP line.",
        "mergeTags": [
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.mc_sms_2",
        "name": "Missed Call - 1 Hour Text",
        "templateRef": "sms_template.mc_sms_2",
        "copyDirection": "One hour later. Ask for a call-back time or offer the booking link; include the phone number.",
        "mergeTags": [
          "custom_values.booking_link",
          "custom_values.business_name",
          "custom_values.business_phone"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.n_sms_1",
        "name": "Nurture Text 1 - One Word",
        "templateRef": "sms_template.n_sms_1",
        "copyDirection": "Day 3. A one-word question that segments (speed / price / getting it right). STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.n_sms_2",
        "name": "Nurture Text 2 - Free Tip",
        "templateRef": "sms_template.n_sms_2",
        "copyDirection": "Day 8. A genuinely useful tip (three questions to ask anyone you hire), offer more on YES. No link.",
        "mergeTags": [
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.n_sms_3",
        "name": "Nurture Text 3 - Midpoint",
        "templateRef": "sms_template.n_sms_3",
        "copyDirection": "Day 15. Personal, from the owner; binary: an opening this week or check back next month.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.n_sms_4",
        "name": "Nurture Text 4 - Any Question",
        "templateRef": "sms_template.n_sms_4",
        "copyDirection": "Day 23. No pitch: did they get their question answered? Invite it.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.n_sms_5",
        "name": "Nurture Text 5 - Last Direct Ask",
        "templateRef": "sms_template.n_sms_5",
        "copyDirection": "Day 30. Last one; YES gets two times; no hard feelings; STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.w_sms_1",
        "name": "Win-back Text 1",
        "templateRef": "sms_template.w_sms_1",
        "copyDirection": "Win-back day 7. Binary: still on the list this quarter, or close the file. STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.w_sms_2",
        "name": "Win-back Text 2",
        "templateRef": "sms_template.w_sms_2",
        "copyDirection": "Win-back day 22. A concrete reason (openings this week) and a YES ask.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.appt_confirm_sms",
        "name": "Appointment Confirmed Text",
        "templateRef": "sms_template.appt_confirm_sms",
        "copyDirection": "On booking. Confirm date/time, how to change it, STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "appointment.start_time"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.appt_24h_sms",
        "name": "Appointment Reminder - 24 Hours",
        "templateRef": "sms_template.appt_24h_sms",
        "copyDirection": "24 hours before. Time, C to confirm / R to reschedule.",
        "mergeTags": [
          "custom_values.business_name",
          "appointment.start_time"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.appt_2h_sms",
        "name": "Appointment Reminder - 2 Hours",
        "templateRef": "sms_template.appt_2h_sms",
        "copyDirection": "2 hours before. Short, warm, reply if late.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name",
          "appointment.start_time"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.ns_sms_1",
        "name": "No-Show Text 1",
        "templateRef": "sms_template.ns_sms_1",
        "copyDirection": "Same day. No guilt, offer a new time this week, YES ask, STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.ns_sms_2",
        "name": "No-Show Text 2",
        "templateRef": "sms_template.ns_sms_2",
        "copyDirection": "Next day. Owner kept times open; ask for a day.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.r_sms_1",
        "name": "Review Request - Text 1",
        "templateRef": "sms_template.r_sms_1",
        "copyDirection": "Two hours after the tag. Thank them, one plain ask, the link, STOP line. No pressure, no incentive (Google forbids it).",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name",
          "custom_values.business_name",
          "custom_values.review_link"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.r_sms_2",
        "name": "Review Request - Text 2",
        "templateRef": "sms_template.r_sms_2",
        "copyDirection": "A week later, the last nudge. Say it is the last one. Link, thanks either way, STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name",
          "custom_values.review_link"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.q_sms_1",
        "name": "Quote Follow-up - Text 1",
        "templateRef": "sms_template.q_sms_1",
        "copyDirection": "One day after the tag. Did it arrive, does anything need explaining. Warm, short, STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name",
          "custom_values.business_name"
        ],
        "conditionalOn": "channels.sms == true"
      },
      {
        "ref": "sms.q_sms_2",
        "name": "Quote Follow-up - Text 2",
        "templateRef": "sms_template.q_sms_2",
        "copyDirection": "Day six. Name the three usual sticking points (timing, price, something else) and ask which. STOP line.",
        "mergeTags": [
          "contact.first_name",
          "custom_values.owner_first_name"
        ],
        "conditionalOn": "channels.sms == true"
      }
    ],
    "workflows": [
      {
        "ref": "workflow.speed_to_lead",
        "name": "Speed to Lead",
        "trigger": {
          "type": "form_submission",
          "formRef": "form.intake"
        },
        "stopOnResponse": true,
        "_design": "Five touches in the first 24 hours (text + email instantly, the contact assigned to the person who takes calls, a call task and an alert to a real person, an opportunity card, then a 2nd and 3rd touch), then the hand-off tag that starts the 30-day nurture as the LAST action (E_NO_HANDOFF). Ends early only if they reply (stopOnResponse) or book (the booking workflow pulls them out).",
        "actions": [
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_new_lead"
          },
          {
            "type": "create_opportunity",
            "pipelineRef": "pipeline.main",
            "stageRef": "stage.new_lead",
            "name": "{{contact.name}} - New Lead"
          },
          {
            "type": "assign_user",
            "userRef": "user.owner"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.stl_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "send_email",
            "emailRef": "email.stl_email_1"
          },
          {
            "type": "internal_notification",
            "userRef": "user.owner",
            "title": "New lead: {{contact.first_name}} {{contact.last_name}}",
            "body": "{{contact.first_name}} just came in from the inquiry form. Phone {{contact.phone}}. Call within 5 minutes; the first text and email already went out."
          },
          {
            "type": "task_notification",
            "userRef": "user.owner",
            "title": "Call {{contact.first_name}} now (new lead)",
            "body": "Speed-to-lead call. {{contact.first_name}} {{contact.last_name}}, {{contact.phone}}, {{contact.email}}. Goal: one question about what they need, then hold a time. Log the outcome in the contact notes.",
            "dueDate": "1"
          },
          {
            "type": "wait",
            "value": 20,
            "unit": "minutes"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.stl_sms_2",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "hours"
          },
          {
            "type": "send_email",
            "emailRef": "email.stl_email_2"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.stl_sms_3",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "add_notes",
            "body": "Speed to Lead finished with no reply (5 touches over 24 hours). Handed off to Lead Nurture (30 days) by the nurture-start tag."
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.nurture_start"
          }
        ]
      },
      {
        "ref": "workflow.missed_call",
        "name": "Missed Call Text-Back",
        "conditionalOn": "channels.sms == true",
        "trigger": {
          "type": "call_status",
          "callStatuses": [
            "no-answer",
            "busy",
            "voicemail"
          ],
          "callDirection": "inbound"
        },
        "stopOnResponse": true,
        "_design": "Fires on an inbound call that was not answered (no-answer / busy / voicemail). Texts back within seconds, tags the contact, alerts a real person and creates a call-back task, then one more text an hour later. Stops the moment they reply.",
        "actions": [
          {
            "type": "send_sms",
            "smsRef": "sms.mc_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.missed_call"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.source_phone"
          },
          {
            "type": "internal_notification",
            "userRef": "user.owner",
            "title": "Missed call: {{contact.first_name}} {{contact.phone}}",
            "body": "An inbound call from {{contact.phone}} was not answered. A text-back already went out. Call back as soon as you can."
          },
          {
            "type": "task_notification",
            "userRef": "user.owner",
            "title": "Call back {{contact.first_name}} (missed call)",
            "body": "Missed inbound call from {{contact.phone}}. The text-back asked what they need; check the conversation first, then call.",
            "dueDate": "1"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "hours"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.mc_sms_2",
            "conditionalOn": "channels.sms == true"
          }
        ]
      },
      {
        "ref": "workflow.lead_nurture",
        "name": "Lead Nurture (30 days)",
        "trigger": {
          "type": "contact_tag",
          "tagRef": "tag.nurture_start"
        },
        "stopOnResponse": true,
        "_design": "Starts from the Speed to Lead hand-off tag. 11 touches (6 emails + 5 texts) across 31 days of waits: give, give, ask. Removes its own trigger tag first so a later hand-off can start it again. Ends by tagging lapsed and handing off to Win-back. Any reply stops it (stopOnResponse) and Replied - Stop & Route takes over.",
        "actions": [
          {
            "type": "remove_contact_tag",
            "tagRef": "tag.nurture_start"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_nurturing"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.n_email_1"
          },
          {
            "type": "wait",
            "value": 2,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.n_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 2,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.n_email_2"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.n_sms_2",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 2,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.n_email_3"
          },
          {
            "type": "wait",
            "value": 4,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.n_email_4"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.n_sms_3",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 5,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.n_email_5"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.n_sms_4",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 4,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.n_email_6"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.n_sms_5",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "add_notes",
            "body": "Lead Nurture (30 days) finished with no reply: 11 touches over 31 days. Tagged lapsed; Win-back starts from the winback-start tag."
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_lapsed"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.winback_start"
          }
        ]
      },
      {
        "ref": "workflow.reply_route",
        "name": "Replied - Stop & Route",
        "trigger": {
          "type": "customer_reply"
        },
        "stopOnResponse": false,
        "_design": "The exit workflow. The moment a contact replies on any channel: pull them out of every sequence, write a note, mark contacted, alert a real person and create a reply task with a 15-minute target.",
        "actions": [
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.speed_to_lead"
          },
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.missed_call",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.lead_nurture"
          },
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.win_back"
          },
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.no_show",
            "conditionalOn": "goal.bookingNeeded == true"
          },
          {
            "type": "add_notes",
            "body": "Contact replied. Removed from Speed to Lead, Missed Call Text-Back, Lead Nurture, Win-back and No-Show Rescue. A human owns the conversation from here."
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_contacted"
          },
          {
            "type": "internal_notification",
            "userRef": "user.owner",
            "title": "{{contact.first_name}} replied",
            "body": "{{contact.first_name}} {{contact.last_name}} replied. All automated sequences stopped. Answer within 15 minutes: {{contact.phone}}"
          },
          {
            "type": "task_notification",
            "userRef": "user.owner",
            "title": "Reply to {{contact.first_name}} (15-minute target)",
            "body": "They replied to a message. Read the conversation, answer the question they asked, and offer one concrete time.",
            "dueDate": "1"
          }
        ]
      },
      {
        "ref": "workflow.win_back",
        "name": "Win-back (30 days)",
        "trigger": {
          "type": "contact_tag",
          "tagRef": "tag.winback_start"
        },
        "stopOnResponse": true,
        "_design": "Starts from the Lead Nurture (or No-Show Rescue) hand-off tag. 5 touches across 31 days of waits, low pressure, one reason to come back per message. Ends by tagging lost. Any reply stops it.",
        "actions": [
          {
            "type": "remove_contact_tag",
            "tagRef": "tag.winback_start"
          },
          {
            "type": "send_email",
            "emailRef": "email.w_email_1"
          },
          {
            "type": "wait",
            "value": 7,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.w_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 7,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.w_email_2"
          },
          {
            "type": "wait",
            "value": 8,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.w_sms_2",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 8,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.w_email_3"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "add_notes",
            "body": "Win-back finished with no reply: 5 touches over 31 days. Tagged lost. The contact stays in the database for future campaigns; nothing else sends automatically."
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_lost"
          }
        ]
      },
      {
        "ref": "workflow.appointment_booked",
        "name": "Appointment Booked - Confirm & Move",
        "trigger": {
          "type": "appointment",
          "appointmentStatus": "confirmed",
          "calendarRef": "calendar.consult"
        },
        "stopOnResponse": false,
        "_design": "On a confirmed booking: stop every sequence, tag booked, alert a real person, send the confirmation email and text, then find the opportunity and move it to the booked stage (create it there if none exists).",
        "actions": [
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.speed_to_lead"
          },
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.lead_nurture"
          },
          {
            "type": "remove_from_workflow",
            "workflowRef": "workflow.win_back"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_booked"
          },
          {
            "type": "internal_notification",
            "userRef": "user.owner",
            "title": "Appointment booked: {{contact.first_name}}",
            "body": "{{contact.first_name}} {{contact.last_name}} booked an appointment for {{appointment.start_time}}. Confirmation sent."
          },
          {
            "type": "send_email",
            "emailRef": "email.appt_confirm_email"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.appt_confirm_sms",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "find_opportunity",
            "pipelineRef": "pipeline.main",
            "found": [
              {
                "type": "update_opportunity",
                "pipelineRef": "pipeline.main",
                "stageRef": "stage.appointment_booked"
              }
            ],
            "notFound": [
              {
                "type": "create_opportunity",
                "pipelineRef": "pipeline.main",
                "stageRef": "stage.appointment_booked",
                "name": "{{contact.name}} - Appointment Booked"
              }
            ]
          }
        ],
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "workflow.appointment_reminders",
        "name": "Appointment Reminders",
        "trigger": {
          "type": "appointment",
          "appointmentStatus": "confirmed",
          "calendarRef": "calendar.consult"
        },
        "stopOnResponse": false,
        "_design": "Same trigger as Confirm & Move, kept separate so the timers stay simple: 24 hours before (text + prep email) and 2 hours before (text). Appointment-relative waits only work under an appointment trigger.",
        "actions": [
          {
            "type": "wait_appointment",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.appt_24h_sms",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "send_email",
            "emailRef": "email.appt_prep_email"
          },
          {
            "type": "wait_appointment",
            "value": 2,
            "unit": "hours"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.appt_2h_sms",
            "conditionalOn": "channels.sms == true"
          }
        ],
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "workflow.no_show",
        "name": "No-Show Rescue",
        "trigger": {
          "type": "appointment",
          "appointmentStatus": "noshow",
          "calendarRef": "calendar.consult"
        },
        "stopOnResponse": true,
        "_design": "On a no-show: tag, alert, call-back task, a warm text and email the same day, a second text next day, a last email 3 days later; then tag lapsed, hand off to Win-back, and move the opportunity back to Contacted (find_opportunity is last because its branches do not rejoin).",
        "actions": [
          {
            "type": "add_contact_tag",
            "tagRef": "tag.no_show"
          },
          {
            "type": "internal_notification",
            "userRef": "user.owner",
            "title": "No-show: {{contact.first_name}}",
            "body": "{{contact.first_name}} {{contact.last_name}} missed their appointment. A rebook text and email went out. Call-back task created."
          },
          {
            "type": "task_notification",
            "userRef": "user.owner",
            "title": "Call {{contact.first_name}} (no-show)",
            "body": "Missed appointment. Call, no guilt, offer two new times.",
            "dueDate": "1"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.ns_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "send_email",
            "emailRef": "email.ns_email_1"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.ns_sms_2",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.ns_email_2"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "add_notes",
            "body": "No-Show Rescue finished with no reply (4 touches over 7 days). Tagged lapsed; Win-back starts from the winback-start tag."
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.lc_lapsed"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.winback_start"
          },
          {
            "type": "find_opportunity",
            "pipelineRef": "pipeline.main",
            "found": [
              {
                "type": "update_opportunity",
                "pipelineRef": "pipeline.main",
                "stageRef": "stage.contacted"
              }
            ],
            "notFound": []
          }
        ],
        "conditionalOn": "goal.bookingNeeded == true"
      },
      {
        "ref": "workflow.review_request",
        "name": "Review Requests",
        "trigger": {
          "type": "contact_tag",
          "tagRef": "tag.review_ask"
        },
        "stopOnResponse": true,
        "_design": "Starts from the review-ask tag, applied when the work is done (by hand or from the stage the operator uses for finished work). Three touches over a week with the Google review link from the review_link custom value. Any reply stops it, so a complaint reaches a person instead of a second nudge. Ends by tagging review-asked so nobody is asked twice.",
        "actions": [
          {
            "type": "remove_contact_tag",
            "tagRef": "tag.review_ask"
          },
          {
            "type": "wait",
            "value": 2,
            "unit": "hours"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.r_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.r_email_1"
          },
          {
            "type": "wait",
            "value": 4,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.r_sms_2",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.review_asked"
          }
        ]
      },
      {
        "ref": "workflow.quote_follow_up",
        "name": "Quote Follow-up",
        "trigger": {
          "type": "contact_tag",
          "tagRef": "tag.quote_sent"
        },
        "stopOnResponse": true,
        "_design": "Starts from the quote-sent tag, applied when a quote goes out (by hand, from a quoting tool, or from a pipeline stage). Four touches over ten days plus one call task, each asking one thing. Any reply stops it. Ends by tagging quote-no-reply so the list of unanswered quotes is one filter away.",
        "actions": [
          {
            "type": "remove_contact_tag",
            "tagRef": "tag.quote_sent"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.quote_open"
          },
          {
            "type": "wait",
            "value": 1,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.q_sms_1",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "wait",
            "value": 2,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.q_email_1"
          },
          {
            "type": "wait",
            "value": 3,
            "unit": "days"
          },
          {
            "type": "send_sms",
            "smsRef": "sms.q_sms_2",
            "conditionalOn": "channels.sms == true"
          },
          {
            "type": "task_notification",
            "userRef": "user.owner",
            "title": "Call {{contact.first_name}} about the quote",
            "body": "The quote went out six days ago with no reply to two texts and an email. One call now usually settles it.",
            "dueDate": "1"
          },
          {
            "type": "wait",
            "value": 4,
            "unit": "days"
          },
          {
            "type": "send_email",
            "emailRef": "email.q_email_2"
          },
          {
            "type": "add_notes",
            "body": "Quote follow-up finished with no reply: 4 touches and a call task over 10 days. Tagged quote-no-reply."
          },
          {
            "type": "remove_contact_tag",
            "tagRef": "tag.quote_open"
          },
          {
            "type": "add_contact_tag",
            "tagRef": "tag.quote_no_reply"
          }
        ]
      }
    ],
    "handoffs": [
      {
        "ref": "handoff.add_staff",
        "conditionalOn": "staff is empty",
        "owner": "OPERATOR-UI",
        "title": "Add the people who get lead alerts and call tasks",
        "trigger": "the brief listed no staff",
        "instruction": "In the sub-account go to Settings > My Staff and add at least one user (yourself is fine): name, email, role. Every \"alert a real person\" and \"call task\" step in the workflows is already built and waiting; the moment a user exists, open each workflow and pick them in the Notify and Task steps (or re-run the build with useSavedPlan:true so the pending steps are re-pointed).",
        "produces": null,
        "successCheck": "At least one user exists and no workflow step still shows \"user pending\"",
        "blocks": [
          "workflow.speed_to_lead",
          "workflow.reply_route",
          "workflow.appointment_booked",
          "workflow.no_show",
          "workflow.missed_call",
          "workflow.quote_follow_up"
        ],
        "_blocksNote": "Workflows with a notification or task pointed at user.__pending__ stay DRAFT until a real user is assigned. Prune entries whose workflow was dropped by conditional pruning."
      },
      {
        "ref": "handoff.phone_number",
        "conditionalOn": "flags includes phone_number_needed",
        "owner": "OPERATOR-UI",
        "title": "Get a phone number in GoHighLevel (so texts and missed-call text-back can work)",
        "trigger": "channels.sms == true && channels.hasPhoneNumber != yes",
        "instruction": "Settings > Phone Numbers > Add Number: buy a local number for the business, then paste it into the business_phone custom value. Every text step and the missed-call text-back are built and wait for this; A2P registration (next) needs the number too.",
        "produces": "cv.business_phone",
        "successCheck": "A number shows under Phone Numbers and business_phone matches it",
        "blocks": [
          "workflow.speed_to_lead",
          "workflow.missed_call",
          "workflow.lead_nurture",
          "workflow.win_back",
          "workflow.appointment_booked",
          "workflow.appointment_reminders",
          "workflow.no_show"
        ]
      },
      {
        "ref": "handoff.business_details",
        "owner": "OPERATOR-UI",
        "title": "Confirm your business phone and the name messages are signed with",
        "trigger": "always (30 seconds)",
        "instruction": "Settings > Custom Values: set business_phone to the number customers should call or text back, and owner_first_name to the first name every email is signed with. The build pre-fills both from the intake when it can.",
        "produces": "cv.owner_first_name",
        "successCheck": "business_phone and owner_first_name show real values, not blanks",
        "blocks": [
          "cv.owner_first_name"
        ]
      },
      {
        "ref": "handoff.calendar_oauth",
        "conditionalOn": "flags includes calendar_oauth_needed && goal.bookingNeeded == true",
        "owner": "OPERATOR-UI",
        "title": "Connect your calendar (Google / Outlook)",
        "trigger": "goal.bookingNeeded == true && channels.calendarConnected == false",
        "instruction": "Open the Consultation calendar > Connections and authorize your Google or Outlook account. This login can only be approved by you. Then copy the booking link into the booking_link custom value.",
        "produces": "cv.booking_link",
        "successCheck": "Calendar shows a connected external account and the booking link resolves",
        "blocks": [
          "cv.booking_link"
        ]
      },
      {
        "ref": "handoff.assign_calendar_staff",
        "conditionalOn": "business.teamSize != 'Just me' && goal.bookingNeeded == true",
        "owner": "OPERATOR-UI",
        "title": "Assign who takes appointments on the calendar",
        "trigger": "a team account: Blueprint will not guess who books",
        "instruction": "Open the Consultation calendar > Team and add the people who take these appointments. Blueprint auto-assigns only when the account has exactly one user.",
        "produces": null,
        "successCheck": "The calendar has at least one assigned team member",
        "blocks": [
          "calendar.consult"
        ]
      },
      {
        "ref": "handoff.a2p",
        "conditionalOn": "flags includes needs_a2p",
        "owner": "OPERATOR-EXT",
        "title": "Register A2P 10DLC (so texts can send)",
        "trigger": "channels.sms == true",
        "instruction": "Submit your A2P brand and campaign through the GHL Trust Center / your carrier. Every text step is built but the SMS-bearing workflows stay DRAFT and will not send until this is approved (7-14 day review). Save your full submission package before submitting.",
        "produces": null,
        "successCheck": "A2P campaign status shows submitted or approved",
        "blocks": [
          "workflow.speed_to_lead",
          "workflow.missed_call",
          "workflow.lead_nurture",
          "workflow.win_back",
          "workflow.appointment_booked",
          "workflow.appointment_reminders",
          "workflow.no_show",
          "sms.stl_sms_1",
          "sms.stl_sms_2",
          "sms.stl_sms_3",
          "sms.mc_sms_1",
          "sms.mc_sms_2",
          "sms.n_sms_1",
          "sms.n_sms_2",
          "sms.n_sms_3",
          "sms.n_sms_4",
          "sms.n_sms_5",
          "sms.w_sms_1",
          "sms.w_sms_2",
          "sms.appt_confirm_sms",
          "sms.appt_24h_sms",
          "sms.appt_2h_sms",
          "sms.ns_sms_1",
          "sms.ns_sms_2",
          "workflow.review_request",
          "sms.r_sms_1",
          "sms.r_sms_2",
          "workflow.quote_follow_up",
          "sms.q_sms_1",
          "sms.q_sms_2"
        ],
        "_blocksNote": "Lists every SMS-bearing WORKFLOW ref (so they stay DRAFT) plus the sms.* asset refs. After conditional pruning, drop any entry whose workflow/asset was removed."
      },
      {
        "ref": "handoff.stripe",
        "conditionalOn": "flags includes stripe_not_connected",
        "owner": "OPERATOR-EXT",
        "title": "Connect Stripe (to take payment)",
        "trigger": "channels.payment != 'Stripe connected'",
        "instruction": "Connect Stripe in Payments > Integrations and create your products / prices. The landing page is built; the money connection is yours to authorize.",
        "produces": null,
        "successCheck": "Stripe shows connected and products exist",
        "blocks": []
      },
      {
        "ref": "handoff.email_domain",
        "conditionalOn": "flags includes email_domain_needed",
        "owner": "OPERATOR-UI",
        "title": "Set up your sending email",
        "trigger": "channels.email == false",
        "instruction": "Connect a sending domain / mailbox in Settings > Email Services so every email below sends from your address instead of a default.",
        "produces": null,
        "successCheck": "A verified sending domain / from-address exists",
        "blocks": [
          "email.stl_email_1",
          "email.stl_email_2",
          "email.n_email_1",
          "email.n_email_2",
          "email.n_email_3",
          "email.n_email_4",
          "email.n_email_5",
          "email.n_email_6",
          "email.w_email_1",
          "email.w_email_2",
          "email.w_email_3",
          "email.appt_confirm_email",
          "email.appt_prep_email",
          "email.ns_email_1",
          "email.ns_email_2"
        ]
      },
      {
        "ref": "handoff.review_link",
        "owner": "OPERATOR-UI",
        "title": "Paste your Google review link, then tag finished work review-ask",
        "trigger": "always",
        "instruction": "In your Google Business Profile, open Ask for reviews and copy the short link. Paste it into the review_link custom value. From then on, add the tag review-ask to a contact when the work is done (or automate it from the stage you use for finished work); the requests start from the tag and stop the moment they reply.",
        "produces": "cv.review_link",
        "successCheck": "The review_link custom value opens your Google review form, and a test contact tagged review-ask receives the first text two hours later",
        "blocks": [
          "cv.review_link"
        ]
      },
      {
        "ref": "handoff.quote_tag",
        "owner": "OPERATOR-UI",
        "title": "Tag a contact quote-sent when a quote goes out (starts the follow-up)",
        "trigger": "always",
        "instruction": "When a quote goes out, add the tag quote-sent to the contact, by hand or automated from your quoting tool or a pipeline stage. The follow-up starts from the tag, asks one thing per touch, and stops the moment they reply.",
        "produces": null,
        "successCheck": "A test contact tagged quote-sent receives the first text one day later",
        "blocks": []
      }
    ]
  }
}
