@elitedcs/ghl-mcp 3.71.0 → 3.72.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -2
- package/README.md +4 -4
- package/dist/capture-helper.js +10 -1
- package/dist/index.js +8052 -2156
- package/guide/guide.html +2 -1
- package/package.json +5 -8
- package/skills/blueprint/SKILL.md +2 -0
- package/skills/blueprint/examples/medspa-approval-view.md +58 -53
- package/skills/blueprint/examples/medspa-brief.json +70 -8
- package/skills/blueprint/examples/medspa-build-plan.json +1435 -123
- package/skills/blueprint/examples/medspa-dry-run-report.md +3 -1
- package/skills/blueprint/examples/sample-approval-view.md +20 -61
- package/skills/blueprint/examples/sample-brief.json +95 -7
- package/skills/blueprint/examples/sample-build-plan.json +1448 -119
- package/skills/blueprint/examples/validate-plan.cjs +195 -13
- package/skills/blueprint/presets/clinic.md +60 -0
- package/skills/blueprint/presets/clinic.preset.json +1737 -0
- package/skills/blueprint/presets/coach.md +58 -0
- package/skills/blueprint/presets/coach.preset.json +1723 -0
- package/skills/blueprint/presets/ecommerce.md +54 -0
- package/skills/blueprint/presets/ecommerce.preset.json +1287 -0
- package/skills/blueprint/presets/generic-client.md +49 -27
- package/skills/blueprint/presets/generic-client.preset.json +1552 -122
- package/skills/blueprint/presets/local-service.md +58 -0
- package/skills/blueprint/presets/local-service.preset.json +1733 -0
- package/skills/blueprint/presets/med-spa.md +47 -48
- package/skills/blueprint/presets/med-spa.preset.json +1557 -111
- package/skills/blueprint/references/agency-os-detection.md +1 -1
- package/skills/blueprint/references/brief-schema.md +48 -1
- package/skills/blueprint/references/build-plan-schema.md +66 -5
- package/skills/blueprint/references/copy-guide.md +167 -0
- package/skills/blueprint/references/intake-question-set.md +64 -3
- package/skills/blueprint/references/preset-format.md +97 -51
- package/templates/action-schemas.json +12 -0
- package/templates/clinic-medspa.json +1 -1
- package/skills/blueprint/presets/clinic-launch-a2p.md +0 -39
- package/skills/blueprint/presets/clinic-launch-a2p.preset.json +0 -337
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"presetId": "med_spa",
|
|
3
|
-
"presetVersion": "
|
|
3
|
+
"presetVersion": "2.0.0",
|
|
4
4
|
"schemaVersion": "0.1",
|
|
5
5
|
"title": "Med Spa",
|
|
6
|
-
"description": "The default GHL Command Blueprint reference preset. A med-spa lead-to-member system:
|
|
6
|
+
"description": "The default GHL Command Blueprint reference preset, v2 depth. A med-spa lead-to-member system: Patient Journey pipeline, lead-source / service-interest / appointment fields, source + lifecycle + interest tags, a round-robin consult calendar, an A2P-compliant intake form + funnel, 15 email + 17 SMS send-ready templates, and 8 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), Consult Booked - Confirm & Move, Consult Reminders, No-Show Rescue. Staff alerts and call tasks on every workflow that needs a human. SMS-bearing workflows stay DRAFT behind the A2P handoff.",
|
|
7
7
|
"default": true,
|
|
8
8
|
"selectors": {
|
|
9
|
-
"businessTypes": [
|
|
10
|
-
|
|
9
|
+
"businessTypes": [
|
|
10
|
+
"Med spa",
|
|
11
|
+
"Medical spa",
|
|
12
|
+
"Medical aesthetics",
|
|
13
|
+
"Aesthetics",
|
|
14
|
+
"Med Spa / Aesthetics"
|
|
15
|
+
],
|
|
16
|
+
"aliases": [
|
|
17
|
+
"med_spa",
|
|
18
|
+
"medspa",
|
|
19
|
+
"medical_spa",
|
|
20
|
+
"aesthetics",
|
|
21
|
+
"injectables"
|
|
22
|
+
]
|
|
11
23
|
},
|
|
12
|
-
"source": "ghl-command showcase Modules 0-7 + the
|
|
24
|
+
"source": "ghl-command showcase Modules 0-7 + proven med-spa builds; v2 depth per the owner review of 2026-08-26 (every workflow must do real work; nurture never under 30 days; copy to the Gary V / Hormozi standard in references/copy-guide.md).",
|
|
13
25
|
"conventions": {
|
|
14
|
-
"triggerTokens": "Use ONLY the executor's native trigger types so triggers auto-build
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
26
|
+
"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.",
|
|
27
|
+
"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.",
|
|
28
|
+
"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.",
|
|
29
|
+
"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`).",
|
|
30
|
+
"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.",
|
|
31
|
+
"a2pGating": "handoff.a2p.blocks MUST list each SMS-bearing WORKFLOW ref (not just sms.* assets); only an explicit workflow.* ref keeps a workflow DRAFT.",
|
|
32
|
+
"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.",
|
|
33
|
+
"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."
|
|
19
34
|
},
|
|
20
35
|
"skeleton": {
|
|
36
|
+
"users": {
|
|
37
|
+
"fillFrom": "team.staff",
|
|
38
|
+
"transform": "userList",
|
|
39
|
+
"default": [],
|
|
40
|
+
"_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)."
|
|
41
|
+
},
|
|
21
42
|
"pipelines": [
|
|
22
43
|
{
|
|
23
44
|
"ref": "pipeline.patient_journey",
|
|
@@ -26,42 +47,232 @@
|
|
|
26
47
|
"fillFrom": "goal.salesStages",
|
|
27
48
|
"transform": "stageList",
|
|
28
49
|
"default": [
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
50
|
+
{
|
|
51
|
+
"ref": "stage.new_lead",
|
|
52
|
+
"name": "New Lead"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"ref": "stage.contacted",
|
|
56
|
+
"name": "Contacted"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"ref": "stage.consult_booked",
|
|
60
|
+
"name": "Consult Booked",
|
|
61
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"ref": "stage.showed",
|
|
65
|
+
"name": "Showed",
|
|
66
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"ref": "stage.treated",
|
|
70
|
+
"name": "Treated"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"ref": "stage.member",
|
|
74
|
+
"name": "Member / Rebooked"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"ref": "stage.lost",
|
|
78
|
+
"name": "Lost"
|
|
79
|
+
}
|
|
36
80
|
]
|
|
37
81
|
}
|
|
38
82
|
}
|
|
39
83
|
],
|
|
40
84
|
"customFields": [
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
85
|
+
{
|
|
86
|
+
"ref": "field.lead_source",
|
|
87
|
+
"name": "Lead Source",
|
|
88
|
+
"dataType": "SINGLE_OPTIONS",
|
|
89
|
+
"model": "contact",
|
|
90
|
+
"options": [
|
|
91
|
+
"Website",
|
|
92
|
+
"Instagram",
|
|
93
|
+
"Facebook",
|
|
94
|
+
"Google",
|
|
95
|
+
"Referral",
|
|
96
|
+
"Phone",
|
|
97
|
+
"Walk-in",
|
|
98
|
+
"Other"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"ref": "field.service_interest",
|
|
103
|
+
"name": "Service Interest",
|
|
104
|
+
"dataType": "MULTIPLE_OPTIONS",
|
|
105
|
+
"model": "contact",
|
|
106
|
+
"options": [
|
|
107
|
+
"Injectables / Tox",
|
|
108
|
+
"Dermal Filler",
|
|
109
|
+
"Facials / Skin",
|
|
110
|
+
"Membership",
|
|
111
|
+
"Weight / Body"
|
|
112
|
+
],
|
|
113
|
+
"_optionsNote": "The skill derives these from offer.summary; mirror them with the interest-* tags."
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"ref": "field.top_concern",
|
|
117
|
+
"name": "Top Concern",
|
|
118
|
+
"dataType": "TEXT",
|
|
119
|
+
"model": "contact",
|
|
120
|
+
"_note": "Filled by staff from the speed-to-lead reply (\"the one thing you would change\")."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"ref": "field.appointment_date",
|
|
124
|
+
"name": "Appointment Date",
|
|
125
|
+
"dataType": "DATE",
|
|
126
|
+
"model": "contact",
|
|
127
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"ref": "field.consult_deposit_paid",
|
|
131
|
+
"name": "Consult Deposit Paid",
|
|
132
|
+
"dataType": "CHECKBOX",
|
|
133
|
+
"model": "contact",
|
|
134
|
+
"options": [
|
|
135
|
+
"Deposit paid"
|
|
136
|
+
],
|
|
137
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"ref": "field.lifetime_value",
|
|
141
|
+
"name": "Estimated Lifetime Value",
|
|
142
|
+
"dataType": "MONETORY",
|
|
143
|
+
"model": "contact"
|
|
144
|
+
}
|
|
46
145
|
],
|
|
47
146
|
"tags": [
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
{
|
|
147
|
+
{
|
|
148
|
+
"ref": "tag.source_website",
|
|
149
|
+
"name": "source-website"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"ref": "tag.source_instagram",
|
|
153
|
+
"name": "source-instagram"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"ref": "tag.source_facebook",
|
|
157
|
+
"name": "source-facebook"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"ref": "tag.source_google",
|
|
161
|
+
"name": "source-google"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"ref": "tag.source_referral",
|
|
165
|
+
"name": "source-referral"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"ref": "tag.source_phone",
|
|
169
|
+
"name": "source-phone"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"ref": "tag.source_other",
|
|
173
|
+
"name": "source-other"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"ref": "tag.lc_new_lead",
|
|
177
|
+
"name": "lifecycle-new-lead"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"ref": "tag.lc_contacted",
|
|
181
|
+
"name": "lifecycle-contacted"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"ref": "tag.lc_nurturing",
|
|
185
|
+
"name": "lifecycle-nurturing"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"ref": "tag.lc_booked",
|
|
189
|
+
"name": "lifecycle-booked",
|
|
190
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"ref": "tag.lc_showed",
|
|
194
|
+
"name": "lifecycle-showed",
|
|
195
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"ref": "tag.lc_treated",
|
|
199
|
+
"name": "lifecycle-treated"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"ref": "tag.lc_member",
|
|
203
|
+
"name": "lifecycle-member"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"ref": "tag.lc_lapsed",
|
|
207
|
+
"name": "lifecycle-lapsed"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"ref": "tag.lc_lost",
|
|
211
|
+
"name": "lifecycle-lost"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"ref": "tag.nurture_start",
|
|
215
|
+
"name": "nurture-start"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"ref": "tag.winback_start",
|
|
219
|
+
"name": "winback-start"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"ref": "tag.missed_call",
|
|
223
|
+
"name": "missed-call",
|
|
224
|
+
"conditionalOn": "channels.sms == true"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"ref": "tag.no_show",
|
|
228
|
+
"name": "no-show",
|
|
229
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"ref": "tag.interest_injectables",
|
|
233
|
+
"name": "interest-injectables"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"ref": "tag.interest_filler",
|
|
237
|
+
"name": "interest-filler"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"ref": "tag.interest_facials",
|
|
241
|
+
"name": "interest-facials"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"ref": "tag.interest_membership",
|
|
245
|
+
"name": "interest-membership"
|
|
246
|
+
}
|
|
61
247
|
],
|
|
62
|
-
"_tagNote": "The skill
|
|
248
|
+
"_tagNote": "The skill derives interest-<x> tags from offer.summary at fill time (injectables / filler / facials / membership for a med spa) and mirrors them onto the Service Interest field options. Declared here so they are reviewable.",
|
|
63
249
|
"customValues": [
|
|
64
|
-
{
|
|
250
|
+
{
|
|
251
|
+
"ref": "cv.business_name",
|
|
252
|
+
"name": "business_name",
|
|
253
|
+
"value": "{{business.name}}"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"ref": "cv.business_phone",
|
|
257
|
+
"name": "business_phone",
|
|
258
|
+
"value": "",
|
|
259
|
+
"filledBy": "handoff.business_details",
|
|
260
|
+
"_fill": "the GHL number once one exists (handoff.phone_number), else blank until the operator fills it"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"ref": "cv.owner_first_name",
|
|
264
|
+
"name": "owner_first_name",
|
|
265
|
+
"value": "",
|
|
266
|
+
"filledBy": "handoff.business_details",
|
|
267
|
+
"_fill": "first name of the user resolved for team.notifyName (the person every message is signed by)"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"ref": "cv.booking_link",
|
|
271
|
+
"name": "booking_link",
|
|
272
|
+
"value": "",
|
|
273
|
+
"filledBy": "handoff.calendar_oauth",
|
|
274
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
275
|
+
}
|
|
65
276
|
],
|
|
66
277
|
"calendars": [
|
|
67
278
|
{
|
|
@@ -69,22 +280,69 @@
|
|
|
69
280
|
"conditionalOn": "goal.bookingNeeded == true",
|
|
70
281
|
"name": "{{business.name}} Consultation || Consultation",
|
|
71
282
|
"calendarType": "round_robin",
|
|
72
|
-
"
|
|
283
|
+
"_slotDuration": "Carry the appointment length from the brief (brief.calendars[].durationMinutes, or the words in the calendar answer: \"15 minutes\" \u2192 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).",
|
|
284
|
+
"slotDuration": 30,
|
|
285
|
+
"slotDurationUnit": "mins",
|
|
286
|
+
"teamMemberRefs": [
|
|
287
|
+
"user.owner"
|
|
288
|
+
],
|
|
289
|
+
"openHours": [
|
|
290
|
+
{
|
|
291
|
+
"daysOfTheWeek": [
|
|
292
|
+
1,
|
|
293
|
+
2,
|
|
294
|
+
3,
|
|
295
|
+
4,
|
|
296
|
+
5
|
|
297
|
+
],
|
|
298
|
+
"hours": [
|
|
299
|
+
{
|
|
300
|
+
"openHour": 9,
|
|
301
|
+
"openMinute": 0,
|
|
302
|
+
"closeHour": 17,
|
|
303
|
+
"closeMinute": 0
|
|
304
|
+
}
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
],
|
|
73
308
|
"availabilityType": 0,
|
|
309
|
+
"slotDuration": 30,
|
|
310
|
+
"slotBuffer": 10,
|
|
74
311
|
"requiresStaff": true,
|
|
75
|
-
"notes": "Default Mon-Fri 9-5 from business.hours; operator edits after build.
|
|
312
|
+
"notes": "Default Mon-Fri 9-5 from business.hours; operator edits after build. teamMemberRefs points at the plan users who take consults (user.owner by default); with no staff in the brief it is emptied and handoff.assign_calendar_staff applies."
|
|
76
313
|
}
|
|
77
314
|
],
|
|
315
|
+
"_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.",
|
|
78
316
|
"forms": [
|
|
79
317
|
{
|
|
80
318
|
"ref": "form.intake",
|
|
81
319
|
"name": "{{business.name}} New Client Inquiry || New Client Inquiry",
|
|
82
320
|
"fields": [
|
|
83
|
-
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
321
|
+
{
|
|
322
|
+
"type": "standard",
|
|
323
|
+
"key": "first_name",
|
|
324
|
+
"required": true
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"type": "standard",
|
|
328
|
+
"key": "last_name",
|
|
329
|
+
"required": false
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"type": "standard",
|
|
333
|
+
"key": "email",
|
|
334
|
+
"required": true
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"type": "standard",
|
|
338
|
+
"key": "phone",
|
|
339
|
+
"required": true
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"type": "custom",
|
|
343
|
+
"fieldRef": "field.service_interest",
|
|
344
|
+
"required": false
|
|
345
|
+
}
|
|
88
346
|
]
|
|
89
347
|
}
|
|
90
348
|
],
|
|
@@ -96,10 +354,10 @@
|
|
|
96
354
|
"pages": [
|
|
97
355
|
{
|
|
98
356
|
"ref": "page.optin",
|
|
99
|
-
"name": "{{offer.leadMagnet}} || Free Assessment",
|
|
357
|
+
"name": "{{offer.leadMagnet}} || Free Skin Assessment",
|
|
100
358
|
"role": "optin",
|
|
101
359
|
"formRef": "form.intake",
|
|
102
|
-
"copyDirection": "OPTIN page per templates/funnel-page-content-template.md: Hero (one H1 = the offer promise) + GEO quotable summary
|
|
360
|
+
"copyDirection": "OPTIN page per templates/funnel-page-content-template.md: Hero (one H1 = the offer promise, e.g. \"Look rested, not done\") + GEO quotable summary + 3-5 outcome-led benefits grounded in offer + audience + the A2P-compliant capture form (form.intake) with a NOT-pre-checked SMS consent checkbox carrying the four disclosures, visible business legal name + mailing address, Privacy/Terms links + a 4-8 Q FAQ with FAQPage JSON-LD + NAP/legal footer. A2P block is MANDATORY."
|
|
103
361
|
},
|
|
104
362
|
{
|
|
105
363
|
"ref": "page.thankyou",
|
|
@@ -107,123 +365,1270 @@
|
|
|
107
365
|
"role": "confirmation",
|
|
108
366
|
"calendarRef": "calendar.consult",
|
|
109
367
|
"conditionalOn": "goal.bookingNeeded == true",
|
|
110
|
-
"copyDirection": "CONFIRMATION page:
|
|
368
|
+
"copyDirection": "CONFIRMATION page: \"Your assessment request is in\", the next-step expectation (a text and email are on the way), and the booking widget via cv.booking_link so they self-schedule now. NAP + Privacy/Terms in the footer."
|
|
111
369
|
}
|
|
112
370
|
]
|
|
113
371
|
}
|
|
114
372
|
],
|
|
373
|
+
"templates": {
|
|
374
|
+
"emails": [
|
|
375
|
+
{
|
|
376
|
+
"ref": "email_template.stl_email_1",
|
|
377
|
+
"name": "Speed to Lead - Instant Email",
|
|
378
|
+
"subject": "Got your request, {{contact.first_name}}",
|
|
379
|
+
"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 {{offer.leadMagnet || free skin assessment}} request just landed with {{custom_values.business_name}}. I'm {{custom_values.owner_first_name}}, and I read every one of these myself.</p><p style=\"margin:0 0 14px;\">Here's what happens next: within a few minutes you'll get a text from this number. Reply with the one thing you'd most like to change, and I'll tell you honestly whether it's a good fit before you spend a dollar.</p><p style=\"margin:0 0 14px;\">If you'd rather skip the back and forth, pick a time that suits you:</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;\">Hold my assessment time</a></p><p style=\"margin:0 0 14px;\">It's 30 minutes, it's free, and nobody will try to sell you something you don't need. That's the whole promise.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"ref": "email_template.stl_email_2",
|
|
383
|
+
"name": "Speed to Lead - 3 Hour Email",
|
|
384
|
+
"subject": "The one question we ask every new client",
|
|
385
|
+
"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 a treatment, we ask one question: what do you want people to notice, and what do you want them not to notice?</p><p style=\"margin:0 0 14px;\">Most people give the same answer. They want to look rested, not different. That answer decides everything about how we work: smaller amounts, the right areas, and a plan you can pause any time.</p><p style=\"margin:0 0 14px;\">Your assessment is where we map that plan. Bring your questions. Bring your skepticism.</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 my time</a></p><p style=\"margin:0 0 14px;\">Or reply to this email with what's on your mind. I answer personally.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"ref": "email_template.n_email_1",
|
|
389
|
+
"name": "Nurture 1 - Refreshed vs Overdone",
|
|
390
|
+
"subject": "Refreshed vs overdone: the real difference",
|
|
391
|
+
"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 number one worry we hear is \"I don't want to look done.\" Fair. Everyone has seen the results that went too far.</p><p style=\"margin:0 0 14px;\">Here is what separates the two, and it isn't luck: the amount, the placement, and the restraint to stop. A good injector treats less than you'd expect on the first visit and adjusts two weeks later once your face has settled. The overdone look comes from doing too much, too fast, in the wrong places.</p><p style=\"margin:0 0 14px;\">That's why our first visit is an assessment, not a sale. We look at your whole face, explain the options in plain language, and tell you what we would not do.</p><p style=\"margin:0 0 14px;\">When you're ready, your assessment is here: <a href=\"{{custom_values.booking_link}}\" style=\"color:#1a56db;text-decoration:underline;\">book a time</a>. No obligation to treat that day.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
"ref": "email_template.n_email_2",
|
|
395
|
+
"name": "Nurture 2 - What Happens at the First Visit",
|
|
396
|
+
"subject": "What actually happens at your first visit",
|
|
397
|
+
"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 put off the first visit because they don't know what's inside the door. So here it is, minute by minute:</p><ul style=\"margin:0 0 14px 20px;padding:0;\"><li style=\"margin:0 0 6px;\">Minutes 0-10: you talk, we listen. What bothers you, what you've tried, what you're nervous about.</li><li style=\"margin:0 0 6px;\">Minutes 10-20: we look at your skin in good light and explain what's causing what.</li><li style=\"margin:0 0 6px;\">Minutes 20-30: you get a written plan with options at different price points. You take it home. No pressure to decide in the chair.</li></ul><p style=\"margin:0 0 14px;\">The objection we hear most is {{audience.objections[0] || price}}. That's exactly why the plan has options: start with the one change that makes the biggest difference and add from there, or don't.</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 my assessment</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"ref": "email_template.n_email_3",
|
|
401
|
+
"name": "Nurture 3 - Why We Treat Less",
|
|
402
|
+
"subject": "Why we treat less than you expect",
|
|
403
|
+
"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 compliment you can get after treatment is \"you look well rested.\" Not \"what did you have done?\"</p><p style=\"margin:0 0 14px;\">That result comes from a rule we don't break: treat conservatively first, then adjust at your two-week check. It's slower than doing everything in one visit. It's also why our clients don't get the frozen or overfilled look, and why they come back.</p><p style=\"margin:0 0 14px;\">If you want to see how that plays out on your face specifically, that's what the assessment 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>"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"ref": "email_template.n_email_4",
|
|
407
|
+
"name": "Nurture 4 - About the Price",
|
|
408
|
+
"subject": "About the price",
|
|
409
|
+
"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 || Our treatments}} are priced by what we actually use, not a flat package you may not need. Because we treat conservatively, most first visits cost less than people expect. Your written plan shows the price of each option before anything happens, and there is never a surprise on the way out.</p><p style=\"margin:0 0 14px;\">If it helps, we'll also show you how to spread your plan over a few months so it fits your budget instead of the other way round.</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 plan</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
"ref": "email_template.n_email_5",
|
|
413
|
+
"name": "Nurture 5 - What Waiting Costs",
|
|
414
|
+
"subject": "What waiting actually costs",
|
|
415
|
+
"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 myth that it's smart to wait until lines get deeper before doing anything. The opposite is true.</p><p style=\"margin:0 0 14px;\">Shallow lines respond to small amounts and look natural. Deep, set-in lines take more product, more visits and more money to soften, and the result is less subtle. Skin is the same: the earlier you start protecting collagen, the less you need to replace later.</p><p style=\"margin:0 0 14px;\">None of that means you have to do anything today. It does mean an assessment now gives you the cheapest set of options you'll ever have.</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 my assessment</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"ref": "email_template.n_email_6",
|
|
419
|
+
"name": "Nurture 6 - Everything in One Place",
|
|
420
|
+
"subject": "Everything you need to decide, in one place",
|
|
421
|
+
"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: your {{offer.leadMagnet || free 30-minute skin assessment}}, with a written plan you keep.</li><li style=\"margin:0 0 6px;\">Where: {{custom_values.business_name}}, {{business.location || our clinic}}.</li><li style=\"margin:0 0 6px;\">Cost of the visit: nothing. Cost of treatment: shown per option, in writing, before anything happens.</li><li style=\"margin:0 0 6px;\">Our rule: treat less first, adjust in two weeks, never overdo it.</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 season.</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 my assessment</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
"ref": "email_template.w_email_1",
|
|
425
|
+
"name": "Win-back 1 - One Question",
|
|
426
|
+
"subject": "One question, {{contact.first_name}}",
|
|
427
|
+
"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 asked {{custom_values.business_name}} about a {{offer.leadMagnet || skin assessment}}, and then life got busy. That's normal.</p><p style=\"margin:0 0 14px;\">One question, and an honest answer is all I need: what stopped you? Timing, price, nerves, 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>"
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"ref": "email_template.w_email_2",
|
|
431
|
+
"name": "Win-back 2 - What Changed",
|
|
432
|
+
"subject": "What's changed since you last looked",
|
|
433
|
+
"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}}: new openings on the calendar, and a written plan that now includes a monthly option for people who want to spread the cost.</p><p style=\"margin:0 0 14px;\">What hasn't changed: the assessment is still free, still 30 minutes, and still ends with a plan you take home instead of a decision in the chair.</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>"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"ref": "email_template.w_email_3",
|
|
437
|
+
"name": "Win-back 3 - The Door Stays Open",
|
|
438
|
+
"subject": "The door stays open",
|
|
439
|
+
"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;\">So here's the deal: your free assessment 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;\">Thank you for considering us. Take care of that skin in the meantime: sunscreen every morning, no exceptions.</p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
"ref": "email_template.appt_confirm_email",
|
|
443
|
+
"name": "Consult Confirmed",
|
|
444
|
+
"subject": "Confirmed, {{contact.first_name}}: your consult details",
|
|
445
|
+
"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 consult at {{custom_values.business_name}} is confirmed for {{appointment.start_time}}.</p><p style=\"margin:0 0 14px;\">What to bring: nothing but your questions. Come with a clean face if you can (no makeup needed) and plan for about 30 minutes.</p><p style=\"margin:0 0 14px;\">What you'll leave with: a written plan with options and prices. No obligation to treat that day.</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>"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"ref": "email_template.appt_prep_email",
|
|
449
|
+
"name": "Consult Prep (day before)",
|
|
450
|
+
"subject": "Tomorrow: 3 things that make your consult better",
|
|
451
|
+
"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 visit more useful:</p><ul style=\"margin:0 0 14px 20px;padding:0;\"><li style=\"margin:0 0 6px;\">Skip makeup if you can. We read skin better bare.</li><li style=\"margin:0 0 6px;\">Bring a photo of yourself from a few years ago. It shows us what \"refreshed\" means to you.</li><li style=\"margin:0 0 6px;\">Write down the one thing you'd change first. 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>"
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"ref": "email_template.ns_email_1",
|
|
455
|
+
"name": "No-Show 1 - We Missed You",
|
|
456
|
+
"subject": "We missed you, {{contact.first_name}} (no guilt)",
|
|
457
|
+
"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 a consult today and it didn't work out. Life happens; nobody here is bothered.</p><p style=\"margin:0 0 14px;\">Your free assessment is still yours. Pick a new time whenever it suits, and if something about the visit 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 assessment</a></p><p style=\"margin:0;\">{{custom_values.owner_first_name}}<br>{{custom_values.business_name}} · {{custom_values.business_phone}}</p></div>"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"ref": "email_template.ns_email_2",
|
|
461
|
+
"name": "No-Show 2 - Still Want This?",
|
|
462
|
+
"subject": "Still want to do this?",
|
|
463
|
+
"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, the calendar is open and the visit is still free.</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>"
|
|
464
|
+
}
|
|
465
|
+
],
|
|
466
|
+
"sms": [
|
|
467
|
+
{
|
|
468
|
+
"ref": "sms_template.stl_sms_1",
|
|
469
|
+
"name": "Speed to Lead - Instant Text",
|
|
470
|
+
"body": "Hi {{contact.first_name}}, it's {{custom_values.owner_first_name}} at {{custom_values.business_name}}. Your {{offer.leadMagnet || free skin assessment}} request is in. What's the one thing you'd most like to change? Reply STOP to opt out."
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"ref": "sms_template.stl_sms_2",
|
|
474
|
+
"name": "Speed to Lead - 20 Minute Text",
|
|
475
|
+
"body": "{{contact.first_name}}, I can hold a 30-min assessment time for you this week. Mornings or afternoons? Or grab one here: {{custom_values.booking_link}}"
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"ref": "sms_template.stl_sms_3",
|
|
479
|
+
"name": "Speed to Lead - Next Day Text",
|
|
480
|
+
"body": "Hi {{contact.first_name}}, {{custom_values.owner_first_name}} again. Not chasing, I just don't want your question to fall through the cracks. Still want to find a time, or is it a \"not now\"?"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"ref": "sms_template.mc_sms_1",
|
|
484
|
+
"name": "Missed Call - Instant Text-Back",
|
|
485
|
+
"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."
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"ref": "sms_template.mc_sms_2",
|
|
489
|
+
"name": "Missed Call - 1 Hour Text",
|
|
490
|
+
"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}}"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"ref": "sms_template.n_sms_1",
|
|
494
|
+
"name": "Nurture Text 1 - One Word",
|
|
495
|
+
"body": "{{contact.first_name}}, quick one from {{custom_values.owner_first_name}} at {{custom_values.business_name}}: is it lines, volume, or skin texture you'd most like to fix first? One word is enough. Reply STOP to opt out."
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"ref": "sms_template.n_sms_2",
|
|
499
|
+
"name": "Nurture Text 2 - Free Tip",
|
|
500
|
+
"body": "Tip from {{custom_values.business_name}}: sunscreen every morning does more for fine lines than any single treatment, and it makes every treatment last longer. Want the short list of what else works? Reply YES."
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"ref": "sms_template.n_sms_3",
|
|
504
|
+
"name": "Nurture Text 3 - Midpoint",
|
|
505
|
+
"body": "{{contact.first_name}}, it's {{custom_values.owner_first_name}}. Still thinking about your skin plan? I have a couple of openings this week. Want one, or should I check back next month?"
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
"ref": "sms_template.n_sms_4",
|
|
509
|
+
"name": "Nurture Text 4 - Any Question",
|
|
510
|
+
"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."
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"ref": "sms_template.n_sms_5",
|
|
514
|
+
"name": "Nurture Text 5 - Last Direct Ask",
|
|
515
|
+
"body": "{{contact.first_name}}, last one from me at {{custom_values.business_name}}. If you want your skin plan this month, reply YES and I'll send two times. If not, no hard feelings. Reply STOP to opt out."
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
"ref": "sms_template.w_sms_1",
|
|
519
|
+
"name": "Win-back Text 1",
|
|
520
|
+
"body": "Hi {{contact.first_name}}, it's {{custom_values.owner_first_name}} at {{custom_values.business_name}}. Is your skin still on the list this season, or should I close your file for now? Reply STOP to opt out."
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
"ref": "sms_template.w_sms_2",
|
|
524
|
+
"name": "Win-back Text 2",
|
|
525
|
+
"body": "{{contact.first_name}}, two openings came up this week at {{custom_values.business_name}}. Want one for your free assessment? Reply YES and I'll hold it."
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
"ref": "sms_template.appt_confirm_sms",
|
|
529
|
+
"name": "Consult Confirmed Text",
|
|
530
|
+
"body": "{{contact.first_name}}, you're confirmed at {{custom_values.business_name}} for {{appointment.start_time}}. Need to change it? Reply here. Reply STOP to opt out."
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"ref": "sms_template.appt_24h_sms",
|
|
534
|
+
"name": "Consult Reminder - 24 Hours",
|
|
535
|
+
"body": "Reminder: your consult at {{custom_values.business_name}} is tomorrow at {{appointment.start_time}}. Reply C to confirm or R to reschedule."
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
"ref": "sms_template.appt_2h_sms",
|
|
539
|
+
"name": "Consult Reminder - 2 Hours",
|
|
540
|
+
"body": "See you in about 2 hours, {{contact.first_name}}. {{custom_values.business_name}}, {{appointment.start_time}}. Reply here if you're running late."
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"ref": "sms_template.ns_sms_1",
|
|
544
|
+
"name": "No-Show Text 1",
|
|
545
|
+
"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."
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"ref": "sms_template.ns_sms_2",
|
|
549
|
+
"name": "No-Show Text 2",
|
|
550
|
+
"body": "{{contact.first_name}}, {{custom_values.owner_first_name}} here. I kept a couple of consult times open for you this week. Want one? Reply with a day that works."
|
|
551
|
+
}
|
|
552
|
+
]
|
|
553
|
+
},
|
|
554
|
+
"_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.",
|
|
115
555
|
"emails": [
|
|
116
|
-
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
556
|
+
{
|
|
557
|
+
"ref": "email.stl_email_1",
|
|
558
|
+
"name": "Speed to Lead - Instant Email",
|
|
559
|
+
"subject": "Got your request, {{contact.first_name}}",
|
|
560
|
+
"templateRef": "email_template.stl_email_1",
|
|
561
|
+
"copyDirection": "Instant. Who I am, what they asked for (offer.leadMagnet), what happens in the next few minutes (a text), 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.",
|
|
562
|
+
"mergeTags": [
|
|
563
|
+
"contact.first_name",
|
|
564
|
+
"custom_values.business_name",
|
|
565
|
+
"custom_values.owner_first_name",
|
|
566
|
+
"custom_values.booking_link",
|
|
567
|
+
"custom_values.business_phone"
|
|
568
|
+
]
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
"ref": "email.stl_email_2",
|
|
572
|
+
"name": "Speed to Lead - 3 Hour Email",
|
|
573
|
+
"subject": "The one question we ask every new client",
|
|
574
|
+
"templateRef": "email_template.stl_email_2",
|
|
575
|
+
"copyDirection": "Second touch, 3 hours in. The reframe (rested, not different), how that decides the way you treat, CTA to book, reply invitation.",
|
|
576
|
+
"mergeTags": [
|
|
577
|
+
"contact.first_name",
|
|
578
|
+
"custom_values.business_name",
|
|
579
|
+
"custom_values.booking_link",
|
|
580
|
+
"custom_values.owner_first_name",
|
|
581
|
+
"custom_values.business_phone"
|
|
582
|
+
]
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
"ref": "email.n_email_1",
|
|
586
|
+
"name": "Nurture 1 - Refreshed vs Overdone",
|
|
587
|
+
"subject": "Refreshed vs overdone: the real difference",
|
|
588
|
+
"templateRef": "email_template.n_email_1",
|
|
589
|
+
"copyDirection": "Day 1 of nurture. Lead with the top fear (looking done), teach what actually separates the two, position the assessment as the safe first step. Give, do not pitch.",
|
|
590
|
+
"mergeTags": [
|
|
591
|
+
"contact.first_name",
|
|
592
|
+
"custom_values.booking_link",
|
|
593
|
+
"custom_values.owner_first_name",
|
|
594
|
+
"custom_values.business_name",
|
|
595
|
+
"custom_values.business_phone"
|
|
596
|
+
]
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
"ref": "email.n_email_2",
|
|
600
|
+
"name": "Nurture 2 - What Happens at the First Visit",
|
|
601
|
+
"subject": "What actually happens at your first visit",
|
|
602
|
+
"templateRef": "email_template.n_email_2",
|
|
603
|
+
"copyDirection": "Day 5. Remove the unknown: the visit minute by minute, then name and answer the top objection (audience.objections[0]) with the written plan + options. One CTA.",
|
|
604
|
+
"mergeTags": [
|
|
605
|
+
"contact.first_name",
|
|
606
|
+
"custom_values.booking_link",
|
|
607
|
+
"custom_values.owner_first_name",
|
|
608
|
+
"custom_values.business_name",
|
|
609
|
+
"custom_values.business_phone"
|
|
610
|
+
]
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"ref": "email.n_email_3",
|
|
614
|
+
"name": "Nurture 3 - Why We Treat Less",
|
|
615
|
+
"subject": "Why we treat less than you expect",
|
|
616
|
+
"templateRef": "email_template.n_email_3",
|
|
617
|
+
"copyDirection": "Day 10. The method as proof: conservative first, adjust at two weeks, why that produces the rested look and repeat clients. Real client results ONLY if the brief supplies them. CTA + reply invite.",
|
|
618
|
+
"mergeTags": [
|
|
619
|
+
"contact.first_name",
|
|
620
|
+
"custom_values.booking_link",
|
|
621
|
+
"custom_values.owner_first_name",
|
|
622
|
+
"custom_values.business_name",
|
|
623
|
+
"custom_values.business_phone"
|
|
624
|
+
]
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
"ref": "email.n_email_4",
|
|
628
|
+
"name": "Nurture 4 - About the Price",
|
|
629
|
+
"subject": "About the price",
|
|
630
|
+
"templateRef": "email_template.n_email_4",
|
|
631
|
+
"copyDirection": "Day 14. Handle cost head-on: priced by what is used, conservative treatment costs less than expected, written prices before anything happens, spread-over-months option. No numbers unless the brief has them.",
|
|
632
|
+
"mergeTags": [
|
|
633
|
+
"contact.first_name",
|
|
634
|
+
"custom_values.booking_link",
|
|
635
|
+
"custom_values.owner_first_name",
|
|
636
|
+
"custom_values.business_name",
|
|
637
|
+
"custom_values.business_phone"
|
|
638
|
+
]
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
"ref": "email.n_email_5",
|
|
642
|
+
"name": "Nurture 5 - What Waiting Costs",
|
|
643
|
+
"subject": "What waiting actually costs",
|
|
644
|
+
"templateRef": "email_template.n_email_5",
|
|
645
|
+
"copyDirection": "Day 20. Cost of inaction without fear-mongering: shallow lines need less, set-in lines need more; earliest assessment = cheapest options. Soft CTA.",
|
|
646
|
+
"mergeTags": [
|
|
647
|
+
"contact.first_name",
|
|
648
|
+
"custom_values.booking_link",
|
|
649
|
+
"custom_values.owner_first_name",
|
|
650
|
+
"custom_values.business_name",
|
|
651
|
+
"custom_values.business_phone"
|
|
652
|
+
]
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
"ref": "email.n_email_6",
|
|
656
|
+
"name": "Nurture 6 - Everything in One Place",
|
|
657
|
+
"subject": "Everything you need to decide, in one place",
|
|
658
|
+
"templateRef": "email_template.n_email_6",
|
|
659
|
+
"copyDirection": "Day 27. The decision sheet: what, where, cost of visit, cost of treatment, the rule, how to book/move. Offer the \"later\" out so a non-reply is a choice. One CTA.",
|
|
660
|
+
"mergeTags": [
|
|
661
|
+
"contact.first_name",
|
|
662
|
+
"custom_values.business_name",
|
|
663
|
+
"custom_values.booking_link",
|
|
664
|
+
"custom_values.owner_first_name",
|
|
665
|
+
"custom_values.business_phone"
|
|
666
|
+
]
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
"ref": "email.w_email_1",
|
|
670
|
+
"name": "Win-back 1 - One Question",
|
|
671
|
+
"subject": "One question, {{contact.first_name}}",
|
|
672
|
+
"templateRef": "email_template.w_email_1",
|
|
673
|
+
"copyDirection": "Win-back day 0. Acknowledge the gap without guilt; ask the one diagnostic question (what stopped you); promise to fix it or leave them alone. No link; a reply is the CTA.",
|
|
674
|
+
"mergeTags": [
|
|
675
|
+
"contact.first_name",
|
|
676
|
+
"custom_values.business_name",
|
|
677
|
+
"custom_values.owner_first_name",
|
|
678
|
+
"custom_values.business_phone"
|
|
679
|
+
]
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"ref": "email.w_email_2",
|
|
683
|
+
"name": "Win-back 2 - What Changed",
|
|
684
|
+
"subject": "What's changed since you last looked",
|
|
685
|
+
"templateRef": "email_template.w_email_2",
|
|
686
|
+
"copyDirection": "Win-back day 14. One real reason to look again (new openings, a monthly option, a seasonal fit) from the brief, then what has not changed (free, 30 min, written plan). One CTA.",
|
|
687
|
+
"mergeTags": [
|
|
688
|
+
"contact.first_name",
|
|
689
|
+
"custom_values.business_name",
|
|
690
|
+
"custom_values.booking_link",
|
|
691
|
+
"custom_values.owner_first_name",
|
|
692
|
+
"custom_values.business_phone"
|
|
693
|
+
]
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
"ref": "email.w_email_3",
|
|
697
|
+
"name": "Win-back 3 - The Door Stays Open",
|
|
698
|
+
"subject": "The door stays open",
|
|
699
|
+
"templateRef": "email_template.w_email_3",
|
|
700
|
+
"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.",
|
|
701
|
+
"mergeTags": [
|
|
702
|
+
"contact.first_name",
|
|
703
|
+
"custom_values.booking_link",
|
|
704
|
+
"custom_values.owner_first_name",
|
|
705
|
+
"custom_values.business_name",
|
|
706
|
+
"custom_values.business_phone"
|
|
707
|
+
]
|
|
708
|
+
},
|
|
709
|
+
{
|
|
710
|
+
"ref": "email.appt_confirm_email",
|
|
711
|
+
"name": "Consult Confirmed",
|
|
712
|
+
"subject": "Confirmed, {{contact.first_name}}: your consult details",
|
|
713
|
+
"templateRef": "email_template.appt_confirm_email",
|
|
714
|
+
"copyDirection": "On booking. Date/time via {{appointment.start_time}}, what to bring, what they leave with, how to move it. Reassuring, short.",
|
|
715
|
+
"mergeTags": [
|
|
716
|
+
"contact.first_name",
|
|
717
|
+
"custom_values.business_name",
|
|
718
|
+
"appointment.start_time",
|
|
719
|
+
"custom_values.booking_link",
|
|
720
|
+
"custom_values.owner_first_name",
|
|
721
|
+
"custom_values.business_phone"
|
|
722
|
+
]
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
"ref": "email.appt_prep_email",
|
|
726
|
+
"name": "Consult Prep (day before)",
|
|
727
|
+
"subject": "Tomorrow: 3 things that make your consult better",
|
|
728
|
+
"templateRef": "email_template.appt_prep_email",
|
|
729
|
+
"copyDirection": "Day before. Three concrete prep items, the time, how to reach us if late. Provider-safe pre-care only (no medical advice without provider review).",
|
|
730
|
+
"mergeTags": [
|
|
731
|
+
"contact.first_name",
|
|
732
|
+
"appointment.start_time",
|
|
733
|
+
"custom_values.business_phone",
|
|
734
|
+
"custom_values.owner_first_name",
|
|
735
|
+
"custom_values.business_name"
|
|
736
|
+
]
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
"ref": "email.ns_email_1",
|
|
740
|
+
"name": "No-Show 1 - We Missed You",
|
|
741
|
+
"subject": "We missed you, {{contact.first_name}} (no guilt)",
|
|
742
|
+
"templateRef": "email_template.ns_email_1",
|
|
743
|
+
"copyDirection": "Same day as the no-show. Zero guilt, the assessment is still theirs, rebook CTA, invite the honest reason.",
|
|
744
|
+
"mergeTags": [
|
|
745
|
+
"contact.first_name",
|
|
746
|
+
"custom_values.booking_link",
|
|
747
|
+
"custom_values.owner_first_name",
|
|
748
|
+
"custom_values.business_name",
|
|
749
|
+
"custom_values.business_phone"
|
|
750
|
+
]
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
"ref": "email.ns_email_2",
|
|
754
|
+
"name": "No-Show 2 - Still Want This?",
|
|
755
|
+
"subject": "Still want to do this?",
|
|
756
|
+
"templateRef": "email_template.ns_email_2",
|
|
757
|
+
"copyDirection": "Day 4 after the no-show. Honest binary: wrong timing (say so) or still want it (calendar is open). One CTA, gracious close.",
|
|
758
|
+
"mergeTags": [
|
|
759
|
+
"contact.first_name",
|
|
760
|
+
"custom_values.booking_link",
|
|
761
|
+
"custom_values.business_name",
|
|
762
|
+
"custom_values.owner_first_name",
|
|
763
|
+
"custom_values.business_phone"
|
|
764
|
+
]
|
|
765
|
+
}
|
|
121
766
|
],
|
|
122
767
|
"sms": [
|
|
123
|
-
{
|
|
124
|
-
|
|
125
|
-
|
|
768
|
+
{
|
|
769
|
+
"ref": "sms.stl_sms_1",
|
|
770
|
+
"name": "Speed to Lead - Instant Text",
|
|
771
|
+
"templateRef": "sms_template.stl_sms_1",
|
|
772
|
+
"copyDirection": "Instant. Name + business, what they asked for, the one-question ask, STOP line. No link in the first text. If brief.voice.signatureLine is short enough, use it verbatim as the second sentence.",
|
|
773
|
+
"mergeTags": [
|
|
774
|
+
"contact.first_name",
|
|
775
|
+
"custom_values.owner_first_name",
|
|
776
|
+
"custom_values.business_name"
|
|
777
|
+
],
|
|
778
|
+
"conditionalOn": "channels.sms == true"
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
"ref": "sms.stl_sms_2",
|
|
782
|
+
"name": "Speed to Lead - 20 Minute Text",
|
|
783
|
+
"templateRef": "sms_template.stl_sms_2",
|
|
784
|
+
"copyDirection": "20 minutes in. Offer to hold a time, a binary question (mornings or afternoons), the booking link.",
|
|
785
|
+
"mergeTags": [
|
|
786
|
+
"contact.first_name",
|
|
787
|
+
"custom_values.booking_link"
|
|
788
|
+
],
|
|
789
|
+
"conditionalOn": "channels.sms == true"
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
"ref": "sms.stl_sms_3",
|
|
793
|
+
"name": "Speed to Lead - Next Day Text",
|
|
794
|
+
"templateRef": "sms_template.stl_sms_3",
|
|
795
|
+
"copyDirection": "Day 1. Not chasing; a binary: find a time or \"not now\". No link.",
|
|
796
|
+
"mergeTags": [
|
|
797
|
+
"contact.first_name",
|
|
798
|
+
"custom_values.owner_first_name"
|
|
799
|
+
],
|
|
800
|
+
"conditionalOn": "channels.sms == true"
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
"ref": "sms.mc_sms_1",
|
|
804
|
+
"name": "Missed Call - Instant Text-Back",
|
|
805
|
+
"templateRef": "sms_template.mc_sms_1",
|
|
806
|
+
"copyDirection": "Seconds after a missed inbound call. Apologize, ask how to help, promise a real person, STOP line.",
|
|
807
|
+
"mergeTags": [
|
|
808
|
+
"custom_values.business_name"
|
|
809
|
+
],
|
|
810
|
+
"conditionalOn": "channels.sms == true"
|
|
811
|
+
},
|
|
812
|
+
{
|
|
813
|
+
"ref": "sms.mc_sms_2",
|
|
814
|
+
"name": "Missed Call - 1 Hour Text",
|
|
815
|
+
"templateRef": "sms_template.mc_sms_2",
|
|
816
|
+
"copyDirection": "One hour later. Ask for a call-back time or offer the booking link; include the phone number.",
|
|
817
|
+
"mergeTags": [
|
|
818
|
+
"custom_values.booking_link",
|
|
819
|
+
"custom_values.business_name",
|
|
820
|
+
"custom_values.business_phone"
|
|
821
|
+
],
|
|
822
|
+
"conditionalOn": "channels.sms == true"
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
"ref": "sms.n_sms_1",
|
|
826
|
+
"name": "Nurture Text 1 - One Word",
|
|
827
|
+
"templateRef": "sms_template.n_sms_1",
|
|
828
|
+
"copyDirection": "Day 3. A one-word question that segments (lines / volume / texture). STOP line (first text of this workflow).",
|
|
829
|
+
"mergeTags": [
|
|
830
|
+
"contact.first_name",
|
|
831
|
+
"custom_values.owner_first_name",
|
|
832
|
+
"custom_values.business_name"
|
|
833
|
+
],
|
|
834
|
+
"conditionalOn": "channels.sms == true"
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
"ref": "sms.n_sms_2",
|
|
838
|
+
"name": "Nurture Text 2 - Free Tip",
|
|
839
|
+
"templateRef": "sms_template.n_sms_2",
|
|
840
|
+
"copyDirection": "Day 8. Give a genuinely useful tip, then offer more with a YES reply. No link.",
|
|
841
|
+
"mergeTags": [
|
|
842
|
+
"custom_values.business_name"
|
|
843
|
+
],
|
|
844
|
+
"conditionalOn": "channels.sms == true"
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
"ref": "sms.n_sms_3",
|
|
848
|
+
"name": "Nurture Text 3 - Midpoint",
|
|
849
|
+
"templateRef": "sms_template.n_sms_3",
|
|
850
|
+
"copyDirection": "Day 15. Personal, from the owner; binary: an opening this week or check back next month.",
|
|
851
|
+
"mergeTags": [
|
|
852
|
+
"contact.first_name",
|
|
853
|
+
"custom_values.owner_first_name"
|
|
854
|
+
],
|
|
855
|
+
"conditionalOn": "channels.sms == true"
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
"ref": "sms.n_sms_4",
|
|
859
|
+
"name": "Nurture Text 4 - Any Question",
|
|
860
|
+
"templateRef": "sms_template.n_sms_4",
|
|
861
|
+
"copyDirection": "Day 23. No pitch: did they get their question answered? Invite it.",
|
|
862
|
+
"mergeTags": [
|
|
863
|
+
"contact.first_name",
|
|
864
|
+
"custom_values.owner_first_name"
|
|
865
|
+
],
|
|
866
|
+
"conditionalOn": "channels.sms == true"
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
"ref": "sms.n_sms_5",
|
|
870
|
+
"name": "Nurture Text 5 - Last Direct Ask",
|
|
871
|
+
"templateRef": "sms_template.n_sms_5",
|
|
872
|
+
"copyDirection": "Day 30. Say it is the last one; YES gets two times; no hard feelings; STOP line.",
|
|
873
|
+
"mergeTags": [
|
|
874
|
+
"contact.first_name",
|
|
875
|
+
"custom_values.business_name"
|
|
876
|
+
],
|
|
877
|
+
"conditionalOn": "channels.sms == true"
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
"ref": "sms.w_sms_1",
|
|
881
|
+
"name": "Win-back Text 1",
|
|
882
|
+
"templateRef": "sms_template.w_sms_1",
|
|
883
|
+
"copyDirection": "Win-back day 7. Binary: still on the list this season, or close the file. STOP line.",
|
|
884
|
+
"mergeTags": [
|
|
885
|
+
"contact.first_name",
|
|
886
|
+
"custom_values.owner_first_name",
|
|
887
|
+
"custom_values.business_name"
|
|
888
|
+
],
|
|
889
|
+
"conditionalOn": "channels.sms == true"
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
"ref": "sms.w_sms_2",
|
|
893
|
+
"name": "Win-back Text 2",
|
|
894
|
+
"templateRef": "sms_template.w_sms_2",
|
|
895
|
+
"copyDirection": "Win-back day 22. A concrete reason (openings this week) and a YES ask.",
|
|
896
|
+
"mergeTags": [
|
|
897
|
+
"contact.first_name",
|
|
898
|
+
"custom_values.business_name"
|
|
899
|
+
],
|
|
900
|
+
"conditionalOn": "channels.sms == true"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
"ref": "sms.appt_confirm_sms",
|
|
904
|
+
"name": "Consult Confirmed Text",
|
|
905
|
+
"templateRef": "sms_template.appt_confirm_sms",
|
|
906
|
+
"copyDirection": "On booking. Confirm date/time, how to change it, STOP line.",
|
|
907
|
+
"mergeTags": [
|
|
908
|
+
"contact.first_name",
|
|
909
|
+
"custom_values.business_name",
|
|
910
|
+
"appointment.start_time"
|
|
911
|
+
],
|
|
912
|
+
"conditionalOn": "channels.sms == true"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
"ref": "sms.appt_24h_sms",
|
|
916
|
+
"name": "Consult Reminder - 24 Hours",
|
|
917
|
+
"templateRef": "sms_template.appt_24h_sms",
|
|
918
|
+
"copyDirection": "24 hours before. Time, C to confirm / R to reschedule.",
|
|
919
|
+
"mergeTags": [
|
|
920
|
+
"custom_values.business_name",
|
|
921
|
+
"appointment.start_time"
|
|
922
|
+
],
|
|
923
|
+
"conditionalOn": "channels.sms == true"
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
"ref": "sms.appt_2h_sms",
|
|
927
|
+
"name": "Consult Reminder - 2 Hours",
|
|
928
|
+
"templateRef": "sms_template.appt_2h_sms",
|
|
929
|
+
"copyDirection": "2 hours before. Short, warm, reply if late.",
|
|
930
|
+
"mergeTags": [
|
|
931
|
+
"contact.first_name",
|
|
932
|
+
"custom_values.business_name",
|
|
933
|
+
"appointment.start_time"
|
|
934
|
+
],
|
|
935
|
+
"conditionalOn": "channels.sms == true"
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"ref": "sms.ns_sms_1",
|
|
939
|
+
"name": "No-Show Text 1",
|
|
940
|
+
"templateRef": "sms_template.ns_sms_1",
|
|
941
|
+
"copyDirection": "Same day. No guilt, offer a new time this week, YES ask, STOP line.",
|
|
942
|
+
"mergeTags": [
|
|
943
|
+
"contact.first_name",
|
|
944
|
+
"custom_values.business_name"
|
|
945
|
+
],
|
|
946
|
+
"conditionalOn": "channels.sms == true"
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
"ref": "sms.ns_sms_2",
|
|
950
|
+
"name": "No-Show Text 2",
|
|
951
|
+
"templateRef": "sms_template.ns_sms_2",
|
|
952
|
+
"copyDirection": "Next day. Owner kept times open; ask for a day.",
|
|
953
|
+
"mergeTags": [
|
|
954
|
+
"contact.first_name",
|
|
955
|
+
"custom_values.owner_first_name"
|
|
956
|
+
],
|
|
957
|
+
"conditionalOn": "channels.sms == true"
|
|
958
|
+
}
|
|
126
959
|
],
|
|
127
960
|
"workflows": [
|
|
128
961
|
{
|
|
129
962
|
"ref": "workflow.speed_to_lead",
|
|
130
963
|
"name": "Speed to Lead",
|
|
131
|
-
"trigger": {
|
|
964
|
+
"trigger": {
|
|
965
|
+
"type": "form_submission",
|
|
966
|
+
"formRef": "form.intake"
|
|
967
|
+
},
|
|
968
|
+
"stopOnResponse": true,
|
|
969
|
+
"_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).",
|
|
970
|
+
"actions": [
|
|
971
|
+
{
|
|
972
|
+
"type": "add_contact_tag",
|
|
973
|
+
"tagRef": "tag.lc_new_lead"
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
"type": "create_opportunity",
|
|
977
|
+
"pipelineRef": "pipeline.patient_journey",
|
|
978
|
+
"stageRef": "stage.new_lead",
|
|
979
|
+
"name": "{{contact.name}} - New Lead"
|
|
980
|
+
},
|
|
981
|
+
{
|
|
982
|
+
"type": "assign_user",
|
|
983
|
+
"userRef": "user.owner"
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
"type": "send_sms",
|
|
987
|
+
"smsRef": "sms.stl_sms_1",
|
|
988
|
+
"conditionalOn": "channels.sms == true"
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
"type": "send_email",
|
|
992
|
+
"emailRef": "email.stl_email_1"
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
"type": "internal_notification",
|
|
996
|
+
"userRef": "user.owner",
|
|
997
|
+
"title": "New lead: {{contact.first_name}} {{contact.last_name}}",
|
|
998
|
+
"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."
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
"type": "task_notification",
|
|
1002
|
+
"userRef": "user.owner",
|
|
1003
|
+
"title": "Call {{contact.first_name}} now (new lead)",
|
|
1004
|
+
"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.",
|
|
1005
|
+
"dueDate": "1"
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
"type": "wait",
|
|
1009
|
+
"value": 20,
|
|
1010
|
+
"unit": "minutes"
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
"type": "send_sms",
|
|
1014
|
+
"smsRef": "sms.stl_sms_2",
|
|
1015
|
+
"conditionalOn": "channels.sms == true"
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
"type": "wait",
|
|
1019
|
+
"value": 3,
|
|
1020
|
+
"unit": "hours"
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
"type": "send_email",
|
|
1024
|
+
"emailRef": "email.stl_email_2"
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
"type": "wait",
|
|
1028
|
+
"value": 1,
|
|
1029
|
+
"unit": "days"
|
|
1030
|
+
},
|
|
1031
|
+
{
|
|
1032
|
+
"type": "send_sms",
|
|
1033
|
+
"smsRef": "sms.stl_sms_3",
|
|
1034
|
+
"conditionalOn": "channels.sms == true"
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
"type": "add_notes",
|
|
1038
|
+
"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."
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
"type": "add_contact_tag",
|
|
1042
|
+
"tagRef": "tag.nurture_start"
|
|
1043
|
+
}
|
|
1044
|
+
]
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
"ref": "workflow.missed_call",
|
|
1048
|
+
"name": "Missed Call Text-Back",
|
|
1049
|
+
"conditionalOn": "channels.sms == true",
|
|
1050
|
+
"trigger": {
|
|
1051
|
+
"type": "call_status",
|
|
1052
|
+
"callStatuses": [
|
|
1053
|
+
"no-answer",
|
|
1054
|
+
"busy",
|
|
1055
|
+
"voicemail"
|
|
1056
|
+
],
|
|
1057
|
+
"callDirection": "inbound"
|
|
1058
|
+
},
|
|
132
1059
|
"stopOnResponse": true,
|
|
1060
|
+
"_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.",
|
|
133
1061
|
"actions": [
|
|
134
|
-
{
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{
|
|
1062
|
+
{
|
|
1063
|
+
"type": "send_sms",
|
|
1064
|
+
"smsRef": "sms.mc_sms_1",
|
|
1065
|
+
"conditionalOn": "channels.sms == true"
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
"type": "add_contact_tag",
|
|
1069
|
+
"tagRef": "tag.missed_call"
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
"type": "add_contact_tag",
|
|
1073
|
+
"tagRef": "tag.source_phone"
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
"type": "internal_notification",
|
|
1077
|
+
"userRef": "user.owner",
|
|
1078
|
+
"title": "Missed call: {{contact.first_name}} {{contact.phone}}",
|
|
1079
|
+
"body": "An inbound call from {{contact.phone}} was not answered. A text-back already went out. Call back as soon as you can."
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
"type": "task_notification",
|
|
1083
|
+
"userRef": "user.owner",
|
|
1084
|
+
"title": "Call back {{contact.first_name}} (missed call)",
|
|
1085
|
+
"body": "Missed inbound call from {{contact.phone}}. The text-back asked what they need; check the conversation first, then call.",
|
|
1086
|
+
"dueDate": "1"
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
"type": "wait",
|
|
1090
|
+
"value": 1,
|
|
1091
|
+
"unit": "hours"
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
"type": "send_sms",
|
|
1095
|
+
"smsRef": "sms.mc_sms_2",
|
|
1096
|
+
"conditionalOn": "channels.sms == true"
|
|
1097
|
+
}
|
|
140
1098
|
]
|
|
141
1099
|
},
|
|
142
1100
|
{
|
|
143
1101
|
"ref": "workflow.lead_nurture",
|
|
144
|
-
"name": "Lead Nurture",
|
|
145
|
-
"trigger": {
|
|
1102
|
+
"name": "Lead Nurture (30 days)",
|
|
1103
|
+
"trigger": {
|
|
1104
|
+
"type": "contact_tag",
|
|
1105
|
+
"tagRef": "tag.nurture_start"
|
|
1106
|
+
},
|
|
146
1107
|
"stopOnResponse": true,
|
|
1108
|
+
"_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.",
|
|
147
1109
|
"actions": [
|
|
148
|
-
{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
1110
|
+
{
|
|
1111
|
+
"type": "remove_contact_tag",
|
|
1112
|
+
"tagRef": "tag.nurture_start"
|
|
1113
|
+
},
|
|
1114
|
+
{
|
|
1115
|
+
"type": "add_contact_tag",
|
|
1116
|
+
"tagRef": "tag.lc_nurturing"
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
"type": "wait",
|
|
1120
|
+
"value": 1,
|
|
1121
|
+
"unit": "days"
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
"type": "send_email",
|
|
1125
|
+
"emailRef": "email.n_email_1"
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
"type": "wait",
|
|
1129
|
+
"value": 2,
|
|
1130
|
+
"unit": "days"
|
|
1131
|
+
},
|
|
1132
|
+
{
|
|
1133
|
+
"type": "send_sms",
|
|
1134
|
+
"smsRef": "sms.n_sms_1",
|
|
1135
|
+
"conditionalOn": "channels.sms == true"
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
"type": "wait",
|
|
1139
|
+
"value": 2,
|
|
1140
|
+
"unit": "days"
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
"type": "send_email",
|
|
1144
|
+
"emailRef": "email.n_email_2"
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
"type": "wait",
|
|
1148
|
+
"value": 3,
|
|
1149
|
+
"unit": "days"
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
"type": "send_sms",
|
|
1153
|
+
"smsRef": "sms.n_sms_2",
|
|
1154
|
+
"conditionalOn": "channels.sms == true"
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
"type": "wait",
|
|
1158
|
+
"value": 2,
|
|
1159
|
+
"unit": "days"
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
"type": "send_email",
|
|
1163
|
+
"emailRef": "email.n_email_3"
|
|
1164
|
+
},
|
|
1165
|
+
{
|
|
1166
|
+
"type": "wait",
|
|
1167
|
+
"value": 4,
|
|
1168
|
+
"unit": "days"
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
"type": "send_email",
|
|
1172
|
+
"emailRef": "email.n_email_4"
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
"type": "wait",
|
|
1176
|
+
"value": 1,
|
|
1177
|
+
"unit": "days"
|
|
1178
|
+
},
|
|
1179
|
+
{
|
|
1180
|
+
"type": "send_sms",
|
|
1181
|
+
"smsRef": "sms.n_sms_3",
|
|
1182
|
+
"conditionalOn": "channels.sms == true"
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
"type": "wait",
|
|
1186
|
+
"value": 5,
|
|
1187
|
+
"unit": "days"
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
"type": "send_email",
|
|
1191
|
+
"emailRef": "email.n_email_5"
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
"type": "wait",
|
|
1195
|
+
"value": 3,
|
|
1196
|
+
"unit": "days"
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
"type": "send_sms",
|
|
1200
|
+
"smsRef": "sms.n_sms_4",
|
|
1201
|
+
"conditionalOn": "channels.sms == true"
|
|
1202
|
+
},
|
|
1203
|
+
{
|
|
1204
|
+
"type": "wait",
|
|
1205
|
+
"value": 4,
|
|
1206
|
+
"unit": "days"
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
"type": "send_email",
|
|
1210
|
+
"emailRef": "email.n_email_6"
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
"type": "wait",
|
|
1214
|
+
"value": 3,
|
|
1215
|
+
"unit": "days"
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
"type": "send_sms",
|
|
1219
|
+
"smsRef": "sms.n_sms_5",
|
|
1220
|
+
"conditionalOn": "channels.sms == true"
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
"type": "wait",
|
|
1224
|
+
"value": 1,
|
|
1225
|
+
"unit": "days"
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
"type": "add_notes",
|
|
1229
|
+
"body": "Lead Nurture (30 days) finished with no reply: 11 touches over 31 days. Tagged lapsed; Win-back starts from the winback-start tag."
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
"type": "add_contact_tag",
|
|
1233
|
+
"tagRef": "tag.lc_lapsed"
|
|
1234
|
+
},
|
|
1235
|
+
{
|
|
1236
|
+
"type": "add_contact_tag",
|
|
1237
|
+
"tagRef": "tag.winback_start"
|
|
1238
|
+
}
|
|
152
1239
|
]
|
|
153
1240
|
},
|
|
154
1241
|
{
|
|
155
1242
|
"ref": "workflow.reply_route",
|
|
156
|
-
"name": "Replied - Stop
|
|
157
|
-
"trigger": {
|
|
1243
|
+
"name": "Replied - Stop & Route",
|
|
1244
|
+
"trigger": {
|
|
1245
|
+
"type": "customer_reply"
|
|
1246
|
+
},
|
|
158
1247
|
"stopOnResponse": false,
|
|
1248
|
+
"_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.",
|
|
159
1249
|
"actions": [
|
|
160
|
-
{
|
|
161
|
-
|
|
162
|
-
|
|
1250
|
+
{
|
|
1251
|
+
"type": "remove_from_workflow",
|
|
1252
|
+
"workflowRef": "workflow.speed_to_lead"
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
"type": "remove_from_workflow",
|
|
1256
|
+
"workflowRef": "workflow.missed_call",
|
|
1257
|
+
"conditionalOn": "channels.sms == true"
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
"type": "remove_from_workflow",
|
|
1261
|
+
"workflowRef": "workflow.lead_nurture"
|
|
1262
|
+
},
|
|
1263
|
+
{
|
|
1264
|
+
"type": "remove_from_workflow",
|
|
1265
|
+
"workflowRef": "workflow.win_back"
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
"type": "remove_from_workflow",
|
|
1269
|
+
"workflowRef": "workflow.no_show",
|
|
1270
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
1271
|
+
},
|
|
1272
|
+
{
|
|
1273
|
+
"type": "add_notes",
|
|
1274
|
+
"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."
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
"type": "add_contact_tag",
|
|
1278
|
+
"tagRef": "tag.lc_contacted"
|
|
1279
|
+
},
|
|
1280
|
+
{
|
|
1281
|
+
"type": "internal_notification",
|
|
1282
|
+
"userRef": "user.owner",
|
|
1283
|
+
"title": "{{contact.first_name}} replied",
|
|
1284
|
+
"body": "{{contact.first_name}} {{contact.last_name}} replied. All automated sequences stopped. Answer within 15 minutes: {{contact.phone}}"
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
"type": "task_notification",
|
|
1288
|
+
"userRef": "user.owner",
|
|
1289
|
+
"title": "Reply to {{contact.first_name}} (15-minute target)",
|
|
1290
|
+
"body": "They replied to a message. Read the conversation, answer the question they asked, and offer one concrete time.",
|
|
1291
|
+
"dueDate": "1"
|
|
1292
|
+
}
|
|
163
1293
|
]
|
|
164
1294
|
},
|
|
165
1295
|
{
|
|
166
|
-
"ref": "workflow.
|
|
167
|
-
"name": "
|
|
168
|
-
"
|
|
169
|
-
|
|
170
|
-
|
|
1296
|
+
"ref": "workflow.win_back",
|
|
1297
|
+
"name": "Win-back (30 days)",
|
|
1298
|
+
"trigger": {
|
|
1299
|
+
"type": "contact_tag",
|
|
1300
|
+
"tagRef": "tag.winback_start"
|
|
1301
|
+
},
|
|
1302
|
+
"stopOnResponse": true,
|
|
1303
|
+
"_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.",
|
|
171
1304
|
"actions": [
|
|
172
|
-
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
{
|
|
177
|
-
|
|
1305
|
+
{
|
|
1306
|
+
"type": "remove_contact_tag",
|
|
1307
|
+
"tagRef": "tag.winback_start"
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
"type": "send_email",
|
|
1311
|
+
"emailRef": "email.w_email_1"
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
"type": "wait",
|
|
1315
|
+
"value": 7,
|
|
1316
|
+
"unit": "days"
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
"type": "send_sms",
|
|
1320
|
+
"smsRef": "sms.w_sms_1",
|
|
1321
|
+
"conditionalOn": "channels.sms == true"
|
|
1322
|
+
},
|
|
1323
|
+
{
|
|
1324
|
+
"type": "wait",
|
|
1325
|
+
"value": 7,
|
|
1326
|
+
"unit": "days"
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
"type": "send_email",
|
|
1330
|
+
"emailRef": "email.w_email_2"
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
"type": "wait",
|
|
1334
|
+
"value": 8,
|
|
1335
|
+
"unit": "days"
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
"type": "send_sms",
|
|
1339
|
+
"smsRef": "sms.w_sms_2",
|
|
1340
|
+
"conditionalOn": "channels.sms == true"
|
|
1341
|
+
},
|
|
1342
|
+
{
|
|
1343
|
+
"type": "wait",
|
|
1344
|
+
"value": 8,
|
|
1345
|
+
"unit": "days"
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
"type": "send_email",
|
|
1349
|
+
"emailRef": "email.w_email_3"
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
"type": "wait",
|
|
1353
|
+
"value": 1,
|
|
1354
|
+
"unit": "days"
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
"type": "add_notes",
|
|
1358
|
+
"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."
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
"type": "add_contact_tag",
|
|
1362
|
+
"tagRef": "tag.lc_lost"
|
|
1363
|
+
}
|
|
178
1364
|
]
|
|
179
1365
|
},
|
|
180
1366
|
{
|
|
181
|
-
"ref": "workflow.
|
|
182
|
-
"name": "
|
|
183
|
-
"
|
|
184
|
-
|
|
185
|
-
|
|
1367
|
+
"ref": "workflow.appointment_booked",
|
|
1368
|
+
"name": "Consult Booked - Confirm & Move",
|
|
1369
|
+
"trigger": {
|
|
1370
|
+
"type": "appointment",
|
|
1371
|
+
"appointmentStatus": "confirmed",
|
|
1372
|
+
"calendarRef": "calendar.consult"
|
|
1373
|
+
},
|
|
1374
|
+
"stopOnResponse": false,
|
|
1375
|
+
"_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).",
|
|
186
1376
|
"actions": [
|
|
187
|
-
{
|
|
188
|
-
|
|
189
|
-
|
|
1377
|
+
{
|
|
1378
|
+
"type": "remove_from_workflow",
|
|
1379
|
+
"workflowRef": "workflow.speed_to_lead"
|
|
1380
|
+
},
|
|
1381
|
+
{
|
|
1382
|
+
"type": "remove_from_workflow",
|
|
1383
|
+
"workflowRef": "workflow.lead_nurture"
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
"type": "remove_from_workflow",
|
|
1387
|
+
"workflowRef": "workflow.win_back"
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
"type": "add_contact_tag",
|
|
1391
|
+
"tagRef": "tag.lc_booked"
|
|
1392
|
+
},
|
|
1393
|
+
{
|
|
1394
|
+
"type": "internal_notification",
|
|
1395
|
+
"userRef": "user.owner",
|
|
1396
|
+
"title": "Consult booked: {{contact.first_name}}",
|
|
1397
|
+
"body": "{{contact.first_name}} {{contact.last_name}} booked a consult for {{appointment.start_time}}. Confirmation sent."
|
|
1398
|
+
},
|
|
1399
|
+
{
|
|
1400
|
+
"type": "send_email",
|
|
1401
|
+
"emailRef": "email.appt_confirm_email"
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
"type": "send_sms",
|
|
1405
|
+
"smsRef": "sms.appt_confirm_sms",
|
|
1406
|
+
"conditionalOn": "channels.sms == true"
|
|
1407
|
+
},
|
|
190
1408
|
{
|
|
191
1409
|
"type": "find_opportunity",
|
|
192
1410
|
"pipelineRef": "pipeline.patient_journey",
|
|
193
|
-
"_note": "find_opportunity MUST be the last action (its Found/Not-Found branches do not rejoin a linear tail).",
|
|
194
1411
|
"found": [
|
|
195
|
-
{
|
|
196
|
-
|
|
1412
|
+
{
|
|
1413
|
+
"type": "update_opportunity",
|
|
1414
|
+
"pipelineRef": "pipeline.patient_journey",
|
|
1415
|
+
"stageRef": "stage.consult_booked"
|
|
1416
|
+
}
|
|
197
1417
|
],
|
|
198
1418
|
"notFound": [
|
|
199
|
-
{
|
|
1419
|
+
{
|
|
1420
|
+
"type": "create_opportunity",
|
|
1421
|
+
"pipelineRef": "pipeline.patient_journey",
|
|
1422
|
+
"stageRef": "stage.consult_booked",
|
|
1423
|
+
"name": "{{contact.name}} - Consult Booked"
|
|
1424
|
+
}
|
|
200
1425
|
]
|
|
201
1426
|
}
|
|
202
|
-
]
|
|
1427
|
+
],
|
|
1428
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
1429
|
+
},
|
|
1430
|
+
{
|
|
1431
|
+
"ref": "workflow.appointment_reminders",
|
|
1432
|
+
"name": "Consult Reminders",
|
|
1433
|
+
"trigger": {
|
|
1434
|
+
"type": "appointment",
|
|
1435
|
+
"appointmentStatus": "confirmed",
|
|
1436
|
+
"calendarRef": "calendar.consult"
|
|
1437
|
+
},
|
|
1438
|
+
"stopOnResponse": false,
|
|
1439
|
+
"_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.",
|
|
1440
|
+
"actions": [
|
|
1441
|
+
{
|
|
1442
|
+
"type": "wait_appointment",
|
|
1443
|
+
"value": 1,
|
|
1444
|
+
"unit": "days"
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
"type": "send_sms",
|
|
1448
|
+
"smsRef": "sms.appt_24h_sms",
|
|
1449
|
+
"conditionalOn": "channels.sms == true"
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
"type": "send_email",
|
|
1453
|
+
"emailRef": "email.appt_prep_email"
|
|
1454
|
+
},
|
|
1455
|
+
{
|
|
1456
|
+
"type": "wait_appointment",
|
|
1457
|
+
"value": 2,
|
|
1458
|
+
"unit": "hours"
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
"type": "send_sms",
|
|
1462
|
+
"smsRef": "sms.appt_2h_sms",
|
|
1463
|
+
"conditionalOn": "channels.sms == true"
|
|
1464
|
+
}
|
|
1465
|
+
],
|
|
1466
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
1467
|
+
},
|
|
1468
|
+
{
|
|
1469
|
+
"ref": "workflow.no_show",
|
|
1470
|
+
"name": "No-Show Rescue",
|
|
1471
|
+
"trigger": {
|
|
1472
|
+
"type": "appointment",
|
|
1473
|
+
"appointmentStatus": "noshow",
|
|
1474
|
+
"calendarRef": "calendar.consult"
|
|
1475
|
+
},
|
|
1476
|
+
"stopOnResponse": true,
|
|
1477
|
+
"_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).",
|
|
1478
|
+
"actions": [
|
|
1479
|
+
{
|
|
1480
|
+
"type": "add_contact_tag",
|
|
1481
|
+
"tagRef": "tag.no_show"
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
"type": "internal_notification",
|
|
1485
|
+
"userRef": "user.owner",
|
|
1486
|
+
"title": "No-show: {{contact.first_name}}",
|
|
1487
|
+
"body": "{{contact.first_name}} {{contact.last_name}} missed their consult. A rebook text and email went out. Call-back task created."
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
"type": "task_notification",
|
|
1491
|
+
"userRef": "user.owner",
|
|
1492
|
+
"title": "Call {{contact.first_name}} (no-show)",
|
|
1493
|
+
"body": "Missed consult. Call, no guilt, offer two new times.",
|
|
1494
|
+
"dueDate": "1"
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
"type": "send_sms",
|
|
1498
|
+
"smsRef": "sms.ns_sms_1",
|
|
1499
|
+
"conditionalOn": "channels.sms == true"
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
"type": "send_email",
|
|
1503
|
+
"emailRef": "email.ns_email_1"
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
"type": "wait",
|
|
1507
|
+
"value": 1,
|
|
1508
|
+
"unit": "days"
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
"type": "send_sms",
|
|
1512
|
+
"smsRef": "sms.ns_sms_2",
|
|
1513
|
+
"conditionalOn": "channels.sms == true"
|
|
1514
|
+
},
|
|
1515
|
+
{
|
|
1516
|
+
"type": "wait",
|
|
1517
|
+
"value": 3,
|
|
1518
|
+
"unit": "days"
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
"type": "send_email",
|
|
1522
|
+
"emailRef": "email.ns_email_2"
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
"type": "wait",
|
|
1526
|
+
"value": 3,
|
|
1527
|
+
"unit": "days"
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
"type": "add_notes",
|
|
1531
|
+
"body": "No-Show Rescue finished with no reply (4 touches over 7 days). Tagged lapsed; Win-back starts from the winback-start tag."
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
"type": "add_contact_tag",
|
|
1535
|
+
"tagRef": "tag.lc_lapsed"
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
"type": "add_contact_tag",
|
|
1539
|
+
"tagRef": "tag.winback_start"
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
"type": "find_opportunity",
|
|
1543
|
+
"pipelineRef": "pipeline.patient_journey",
|
|
1544
|
+
"found": [
|
|
1545
|
+
{
|
|
1546
|
+
"type": "update_opportunity",
|
|
1547
|
+
"pipelineRef": "pipeline.patient_journey",
|
|
1548
|
+
"stageRef": "stage.contacted"
|
|
1549
|
+
}
|
|
1550
|
+
],
|
|
1551
|
+
"notFound": []
|
|
1552
|
+
}
|
|
1553
|
+
],
|
|
1554
|
+
"conditionalOn": "goal.bookingNeeded == true"
|
|
203
1555
|
}
|
|
204
1556
|
],
|
|
205
1557
|
"handoffs": [
|
|
206
1558
|
{
|
|
207
1559
|
"ref": "handoff.add_staff",
|
|
208
|
-
"conditionalOn": "
|
|
1560
|
+
"conditionalOn": "staff is empty",
|
|
209
1561
|
"owner": "OPERATOR-UI",
|
|
210
|
-
"title": "
|
|
211
|
-
"trigger": "
|
|
212
|
-
"instruction": "In the sub-account
|
|
1562
|
+
"title": "Add the people who get lead alerts and call tasks",
|
|
1563
|
+
"trigger": "the brief listed no staff",
|
|
1564
|
+
"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).",
|
|
213
1565
|
"produces": null,
|
|
214
|
-
"successCheck": "
|
|
215
|
-
"blocks": [
|
|
1566
|
+
"successCheck": "At least one user exists and no workflow step still shows \"user pending\"",
|
|
1567
|
+
"blocks": [
|
|
1568
|
+
"workflow.speed_to_lead",
|
|
1569
|
+
"workflow.reply_route",
|
|
1570
|
+
"workflow.appointment_booked",
|
|
1571
|
+
"workflow.no_show",
|
|
1572
|
+
"workflow.missed_call"
|
|
1573
|
+
],
|
|
1574
|
+
"_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."
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
"ref": "handoff.phone_number",
|
|
1578
|
+
"conditionalOn": "flags includes phone_number_needed",
|
|
1579
|
+
"owner": "OPERATOR-UI",
|
|
1580
|
+
"title": "Get a phone number in GoHighLevel (so texts and missed-call text-back can work)",
|
|
1581
|
+
"trigger": "channels.sms == true && channels.hasPhoneNumber != yes",
|
|
1582
|
+
"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.",
|
|
1583
|
+
"produces": "cv.business_phone",
|
|
1584
|
+
"successCheck": "A number shows under Phone Numbers and business_phone matches it",
|
|
1585
|
+
"blocks": [
|
|
1586
|
+
"workflow.speed_to_lead",
|
|
1587
|
+
"workflow.missed_call",
|
|
1588
|
+
"workflow.lead_nurture",
|
|
1589
|
+
"workflow.win_back",
|
|
1590
|
+
"workflow.appointment_booked",
|
|
1591
|
+
"workflow.appointment_reminders",
|
|
1592
|
+
"workflow.no_show"
|
|
1593
|
+
]
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
"ref": "handoff.business_details",
|
|
1597
|
+
"owner": "OPERATOR-UI",
|
|
1598
|
+
"title": "Confirm your business phone and the name messages are signed with",
|
|
1599
|
+
"trigger": "always (30 seconds)",
|
|
1600
|
+
"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.",
|
|
1601
|
+
"produces": "cv.owner_first_name",
|
|
1602
|
+
"successCheck": "business_phone and owner_first_name show real values, not blanks",
|
|
1603
|
+
"blocks": [
|
|
1604
|
+
"cv.owner_first_name"
|
|
1605
|
+
]
|
|
216
1606
|
},
|
|
217
1607
|
{
|
|
218
1608
|
"ref": "handoff.calendar_oauth",
|
|
219
|
-
"conditionalOn": "flags includes calendar_oauth_needed",
|
|
1609
|
+
"conditionalOn": "flags includes calendar_oauth_needed && goal.bookingNeeded == true",
|
|
220
1610
|
"owner": "OPERATOR-UI",
|
|
221
1611
|
"title": "Connect your calendar (Google / Outlook)",
|
|
222
1612
|
"trigger": "goal.bookingNeeded == true && channels.calendarConnected == false",
|
|
223
|
-
"instruction": "Open the
|
|
1613
|
+
"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.",
|
|
224
1614
|
"produces": "cv.booking_link",
|
|
225
1615
|
"successCheck": "Calendar shows a connected external account and the booking link resolves",
|
|
226
|
-
"blocks": [
|
|
1616
|
+
"blocks": [
|
|
1617
|
+
"cv.booking_link"
|
|
1618
|
+
]
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
"ref": "handoff.assign_calendar_staff",
|
|
1622
|
+
"conditionalOn": "business.teamSize != 'Just me' && goal.bookingNeeded == true",
|
|
1623
|
+
"owner": "OPERATOR-UI",
|
|
1624
|
+
"title": "Assign who takes consults on the calendar",
|
|
1625
|
+
"trigger": "a team account: Blueprint will not guess who books",
|
|
1626
|
+
"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.",
|
|
1627
|
+
"produces": null,
|
|
1628
|
+
"successCheck": "The calendar has at least one assigned team member",
|
|
1629
|
+
"blocks": [
|
|
1630
|
+
"calendar.consult"
|
|
1631
|
+
]
|
|
227
1632
|
},
|
|
228
1633
|
{
|
|
229
1634
|
"ref": "handoff.a2p",
|
|
@@ -231,11 +1636,36 @@
|
|
|
231
1636
|
"owner": "OPERATOR-EXT",
|
|
232
1637
|
"title": "Register A2P 10DLC (so texts can send)",
|
|
233
1638
|
"trigger": "channels.sms == true",
|
|
234
|
-
"instruction": "Submit your A2P brand and campaign through the GHL Trust Center / your carrier.
|
|
1639
|
+
"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.",
|
|
235
1640
|
"produces": null,
|
|
236
1641
|
"successCheck": "A2P campaign status shows submitted or approved",
|
|
237
|
-
"blocks": [
|
|
238
|
-
|
|
1642
|
+
"blocks": [
|
|
1643
|
+
"workflow.speed_to_lead",
|
|
1644
|
+
"workflow.missed_call",
|
|
1645
|
+
"workflow.lead_nurture",
|
|
1646
|
+
"workflow.win_back",
|
|
1647
|
+
"workflow.appointment_booked",
|
|
1648
|
+
"workflow.appointment_reminders",
|
|
1649
|
+
"workflow.no_show",
|
|
1650
|
+
"sms.stl_sms_1",
|
|
1651
|
+
"sms.stl_sms_2",
|
|
1652
|
+
"sms.stl_sms_3",
|
|
1653
|
+
"sms.mc_sms_1",
|
|
1654
|
+
"sms.mc_sms_2",
|
|
1655
|
+
"sms.n_sms_1",
|
|
1656
|
+
"sms.n_sms_2",
|
|
1657
|
+
"sms.n_sms_3",
|
|
1658
|
+
"sms.n_sms_4",
|
|
1659
|
+
"sms.n_sms_5",
|
|
1660
|
+
"sms.w_sms_1",
|
|
1661
|
+
"sms.w_sms_2",
|
|
1662
|
+
"sms.appt_confirm_sms",
|
|
1663
|
+
"sms.appt_24h_sms",
|
|
1664
|
+
"sms.appt_2h_sms",
|
|
1665
|
+
"sms.ns_sms_1",
|
|
1666
|
+
"sms.ns_sms_2"
|
|
1667
|
+
],
|
|
1668
|
+
"_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."
|
|
239
1669
|
},
|
|
240
1670
|
{
|
|
241
1671
|
"ref": "handoff.stripe",
|
|
@@ -254,10 +1684,26 @@
|
|
|
254
1684
|
"owner": "OPERATOR-UI",
|
|
255
1685
|
"title": "Set up your sending email",
|
|
256
1686
|
"trigger": "channels.email == false",
|
|
257
|
-
"instruction": "Connect a sending domain / mailbox in Settings > Email Services so
|
|
1687
|
+
"instruction": "Connect a sending domain / mailbox in Settings > Email Services so every email below sends from your address instead of a default.",
|
|
258
1688
|
"produces": null,
|
|
259
1689
|
"successCheck": "A verified sending domain / from-address exists",
|
|
260
|
-
"blocks": [
|
|
1690
|
+
"blocks": [
|
|
1691
|
+
"email.stl_email_1",
|
|
1692
|
+
"email.stl_email_2",
|
|
1693
|
+
"email.n_email_1",
|
|
1694
|
+
"email.n_email_2",
|
|
1695
|
+
"email.n_email_3",
|
|
1696
|
+
"email.n_email_4",
|
|
1697
|
+
"email.n_email_5",
|
|
1698
|
+
"email.n_email_6",
|
|
1699
|
+
"email.w_email_1",
|
|
1700
|
+
"email.w_email_2",
|
|
1701
|
+
"email.w_email_3",
|
|
1702
|
+
"email.appt_confirm_email",
|
|
1703
|
+
"email.appt_prep_email",
|
|
1704
|
+
"email.ns_email_1",
|
|
1705
|
+
"email.ns_email_2"
|
|
1706
|
+
]
|
|
261
1707
|
}
|
|
262
1708
|
]
|
|
263
1709
|
}
|