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