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