@elitedcs/ghl-mcp 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +320 -0
- package/LICENSE +21 -0
- package/README.md +758 -0
- package/dist/index.js +6091 -0
- package/package.json +60 -0
- package/templates/action-schemas.json +333 -0
- package/templates/clinic-medspa.json +270 -0
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elitedcs/ghl-mcp",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "GoHighLevel MCP Server for Claude. 171 tools — full CRM, automation, marketing control, and the only programmatic GHL workflow builder.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ghl-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/index.js",
|
|
11
|
+
"templates/action-schemas.json",
|
|
12
|
+
"templates/clinic-medspa.json",
|
|
13
|
+
"README.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "esbuild src/index.ts --bundle --platform=node --target=node22 --format=cjs --outfile=dist/index.js --packages=external",
|
|
18
|
+
"setup": "node setup-wizard.mjs",
|
|
19
|
+
"start": "node dist/index.js",
|
|
20
|
+
"dev": "tsc --watch",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mcp",
|
|
25
|
+
"model-context-protocol",
|
|
26
|
+
"gohighlevel",
|
|
27
|
+
"ghl",
|
|
28
|
+
"crm",
|
|
29
|
+
"claude",
|
|
30
|
+
"anthropic"
|
|
31
|
+
],
|
|
32
|
+
"author": "Elite DCs, LLC",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"homepage": "https://elitedcs.com/ghl-mcp-server",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/drjerryrelth/elite-dcs-ghl-mcp.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/drjerryrelth/elite-dcs-ghl-mcp/issues"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=22"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
50
|
+
"dotenv": "^16.5.0",
|
|
51
|
+
"zod": "^3.24.4"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@clack/prompts": "^1.1.0",
|
|
55
|
+
"@types/node": "^22.15.3",
|
|
56
|
+
"esbuild": "^0.27.4",
|
|
57
|
+
"open": "^11.0.0",
|
|
58
|
+
"typescript": "^5.8.3"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_description": "AUTHORITATIVE REFERENCE: Correct GHL workflow action attribute schemas. Derived from real working workflows built in GHL UI. ALL sessions MUST use these exact formats.",
|
|
3
|
+
"_version": "2.0 — 2026-03-24",
|
|
4
|
+
"_critical_rules": [
|
|
5
|
+
"NEVER use 'body' for emails — use 'html' with HTML markup",
|
|
6
|
+
"NEVER use 'tagName' — use 'tags' array",
|
|
7
|
+
"NEVER use 'duration' for waits — use startAfter object",
|
|
8
|
+
"NEVER use singular min units — real GHL uses 'minutes'",
|
|
9
|
+
"ALWAYS include 'attachments: []' on SMS actions",
|
|
10
|
+
"ALWAYS include 'trackingOptions' on email actions",
|
|
11
|
+
"ALWAYS include all 5 fields on wait actions (type, startAfter, isHybridAction, hybridActionType, transitions)",
|
|
12
|
+
"ALWAYS use 'parent' AND 'parentKey' on branch nodes",
|
|
13
|
+
"ALWAYS use 'sibling' arrays on branch-yes and branch-no nodes",
|
|
14
|
+
"NEVER use if_else as a single flat action — it is only valid on condition-node, branch-yes, and branch-no nodes",
|
|
15
|
+
"ALWAYS include workflow_id ARRAY in remove_from_workflow (not just workflowId string)",
|
|
16
|
+
"For linear workflows, the buildActionChain needs BOTH next (forward) and parentKey (backward) on every action",
|
|
17
|
+
"Keep workflows under 40 actions to avoid GHL UI renderer freezes",
|
|
18
|
+
"Use separate exit workflows instead of inline if/else branching for nurture sequences"
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
"add_contact_tag": {
|
|
22
|
+
"example": {
|
|
23
|
+
"tags": ["tag-name-here"]
|
|
24
|
+
},
|
|
25
|
+
"notes": "Use 'tags' ARRAY, NOT 'tagName' string. Tag must exist in the location."
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
"remove_contact_tag": {
|
|
29
|
+
"example": {
|
|
30
|
+
"tags": ["tag-to-remove"]
|
|
31
|
+
},
|
|
32
|
+
"notes": "Same format as add_contact_tag but action type is 'remove_contact_tag'."
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
"sms": {
|
|
36
|
+
"example": {
|
|
37
|
+
"body": "Hi {{contact.first_name}}, your message here.",
|
|
38
|
+
"attachments": []
|
|
39
|
+
},
|
|
40
|
+
"notes": "Body supports GHL merge fields. 'attachments' is REQUIRED even if empty array."
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
"email": {
|
|
44
|
+
"example": {
|
|
45
|
+
"subject": "Your Subject Line",
|
|
46
|
+
"html": "<p style=\"margin:0px; padding-left: 0px!important;\">Email body as HTML here.</p>",
|
|
47
|
+
"trackingOptions": {
|
|
48
|
+
"hasTrackingLinks": false,
|
|
49
|
+
"hasUtmTracking": false,
|
|
50
|
+
"hasTags": false
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"notes": "Use 'html' NOT 'body'. Content MUST be HTML with <p> tags. Subject supports merge fields. trackingOptions is REQUIRED."
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
"wait": {
|
|
57
|
+
"example_1hour": {
|
|
58
|
+
"type": "time",
|
|
59
|
+
"startAfter": { "type": "hour", "value": 1, "when": "after" },
|
|
60
|
+
"name": "Wait",
|
|
61
|
+
"isHybridAction": true,
|
|
62
|
+
"hybridActionType": "wait",
|
|
63
|
+
"convertToMultipath": false,
|
|
64
|
+
"transitions": []
|
|
65
|
+
},
|
|
66
|
+
"example_30min": {
|
|
67
|
+
"type": "time",
|
|
68
|
+
"startAfter": { "type": "minutes", "value": 30, "when": "after" },
|
|
69
|
+
"name": "Wait",
|
|
70
|
+
"isHybridAction": true,
|
|
71
|
+
"hybridActionType": "wait",
|
|
72
|
+
"convertToMultipath": false,
|
|
73
|
+
"transitions": []
|
|
74
|
+
},
|
|
75
|
+
"example_3days": {
|
|
76
|
+
"type": "time",
|
|
77
|
+
"startAfter": { "type": "day", "value": 3, "when": "after" },
|
|
78
|
+
"name": "Wait",
|
|
79
|
+
"isHybridAction": true,
|
|
80
|
+
"hybridActionType": "wait",
|
|
81
|
+
"convertToMultipath": false,
|
|
82
|
+
"transitions": []
|
|
83
|
+
},
|
|
84
|
+
"notes": "startAfter.type: 'minutes', 'hour', or 'day'. ALL 5 fields required (type, startAfter, isHybridAction, hybridActionType, transitions). Derived from working GHL UI-built workflows."
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
"internal_notification": {
|
|
88
|
+
"example": {
|
|
89
|
+
"type": "notification",
|
|
90
|
+
"notification": {
|
|
91
|
+
"body": "Notification body with {{contact.first_name}} merge fields",
|
|
92
|
+
"title": "Notification Title",
|
|
93
|
+
"userType": "user",
|
|
94
|
+
"redirectPage": "contact",
|
|
95
|
+
"type": "send_notification",
|
|
96
|
+
"selectedUser": ""
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"notes": "Nested 'notification' object REQUIRED. selectedUser empty string for all users, or specific user ID."
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
"update_contact_field": {
|
|
103
|
+
"example": {
|
|
104
|
+
"type": "update_contact_field",
|
|
105
|
+
"actionType": "update_field_data",
|
|
106
|
+
"fields": [
|
|
107
|
+
{
|
|
108
|
+
"field": "CUSTOM_FIELD_ID",
|
|
109
|
+
"value": "New Value",
|
|
110
|
+
"title": "Field Display Name",
|
|
111
|
+
"type": "text",
|
|
112
|
+
"date": ""
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
"notes": "'field' is the custom field ID, not the name. Use get_custom_fields to find IDs."
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
"add_notes": {
|
|
120
|
+
"example": {
|
|
121
|
+
"html": "<p style=\"padding-left: 0px!important;\">Note content here.</p>",
|
|
122
|
+
"type": "add_notes"
|
|
123
|
+
},
|
|
124
|
+
"notes": "Content MUST be HTML."
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
"task-notification": {
|
|
128
|
+
"example": {
|
|
129
|
+
"assignedTo": "USER_ID",
|
|
130
|
+
"title": "Task Title",
|
|
131
|
+
"dueDate": "1",
|
|
132
|
+
"body": "Task description text",
|
|
133
|
+
"type": "task_notification",
|
|
134
|
+
"__customInputs__": {}
|
|
135
|
+
},
|
|
136
|
+
"notes": "dueDate is days from now as string. assignedTo is a user ID."
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
"remove_from_workflow": {
|
|
140
|
+
"example": {
|
|
141
|
+
"workflowId": "TARGET_WORKFLOW_ID",
|
|
142
|
+
"workflowName": "Target Workflow Name",
|
|
143
|
+
"type": "remove_from_workflow",
|
|
144
|
+
"workflow_id": ["TARGET_WORKFLOW_ID"]
|
|
145
|
+
},
|
|
146
|
+
"notes": "Requires BOTH workflowId (string) AND workflow_id (ARRAY with same ID). Also needs type: 'remove_from_workflow' inside attributes. Derived from GHL UI."
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
"internal_update_opportunity": {
|
|
150
|
+
"example": {
|
|
151
|
+
"__customInputFields__": [
|
|
152
|
+
{
|
|
153
|
+
"filterField": "pipelineId",
|
|
154
|
+
"value": "PIPELINE_ID",
|
|
155
|
+
"valueFieldType": "select",
|
|
156
|
+
"dataType": "SINGLE_OPTIONS"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"filterField": "pipelineStageId",
|
|
160
|
+
"value": "STAGE_ID",
|
|
161
|
+
"valueFieldType": "select",
|
|
162
|
+
"dataType": "SINGLE_OPTIONS"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"workflowsActionType": "INTERNAL",
|
|
166
|
+
"type": "internal_update_opportunity"
|
|
167
|
+
},
|
|
168
|
+
"notes": "Use action type internal_update_opportunity. Use pipeline and stage IDs (not names). Use get_pipelines or list_pipelines_full to find IDs FIRST. CRITICAL: If the pipelineId or stageId don't exist in the target sub-account, GHL silently fails this action AND can kill subsequent actions in the workflow. Always verify IDs exist before deploying."
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
"_if_else_branching": {
|
|
172
|
+
"notes": "if_else is a node type discriminator only. Do not send a single flat if_else action.",
|
|
173
|
+
"condition_node": {
|
|
174
|
+
"type": "if_else",
|
|
175
|
+
"cat": "conditions",
|
|
176
|
+
"nodeType": "condition-node",
|
|
177
|
+
"next": ["YES_BRANCH_ID", "NO_BRANCH_ID"],
|
|
178
|
+
"attributes": {
|
|
179
|
+
"currentRecipeType": "HAS_TAG",
|
|
180
|
+
"operator": "and",
|
|
181
|
+
"if": true,
|
|
182
|
+
"conditionName": "HAS_TAG",
|
|
183
|
+
"version": 2,
|
|
184
|
+
"noneBranchName": "None",
|
|
185
|
+
"branches": [{
|
|
186
|
+
"id": "YES_BRANCH_ID",
|
|
187
|
+
"name": "Branch name",
|
|
188
|
+
"segments": [{
|
|
189
|
+
"__segmentId": "SEGMENT_UUID",
|
|
190
|
+
"operator": "and",
|
|
191
|
+
"conditions": [{
|
|
192
|
+
"conditionType": "contact_detail",
|
|
193
|
+
"conditionSubType": "tags",
|
|
194
|
+
"conditionOperator": "index-of-true",
|
|
195
|
+
"conditionValue": ["tag-to-check"],
|
|
196
|
+
"__conditionId": "CONDITION_UUID",
|
|
197
|
+
"__customFieldType__": "standard",
|
|
198
|
+
"nestedDropdownTypes": [],
|
|
199
|
+
"allowIsOperatorTypes": [],
|
|
200
|
+
"ifElseNodeId": "CONDITION_NODE_ID",
|
|
201
|
+
"isWait": false
|
|
202
|
+
}]
|
|
203
|
+
}]
|
|
204
|
+
}]
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"branch_yes": {
|
|
208
|
+
"parentKey": "CONDITION_NODE_ID",
|
|
209
|
+
"parent": "CONDITION_NODE_ID",
|
|
210
|
+
"cat": "conditions",
|
|
211
|
+
"nodeType": "branch-yes",
|
|
212
|
+
"sibling": ["NO_BRANCH_ID"],
|
|
213
|
+
"next": "FIRST_YES_CHILD_ID",
|
|
214
|
+
"attributes": {
|
|
215
|
+
"if": false,
|
|
216
|
+
"conditionName": "HAS_TAG",
|
|
217
|
+
"operator": "and",
|
|
218
|
+
"branches": []
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"branch_no": {
|
|
222
|
+
"parentKey": "CONDITION_NODE_ID",
|
|
223
|
+
"parent": "CONDITION_NODE_ID",
|
|
224
|
+
"cat": "conditions",
|
|
225
|
+
"nodeType": "branch-no",
|
|
226
|
+
"sibling": ["YES_BRANCH_ID"],
|
|
227
|
+
"next": "FIRST_NO_CHILD_ID",
|
|
228
|
+
"attributes": {
|
|
229
|
+
"else": true,
|
|
230
|
+
"conditionName": "HAS_TAG",
|
|
231
|
+
"operator": "and",
|
|
232
|
+
"branches": []
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"branch_child_actions": {
|
|
236
|
+
"first_child": {
|
|
237
|
+
"parent": "BRANCH_YES_OR_NO_ID",
|
|
238
|
+
"parentKey": "BRANCH_YES_OR_NO_ID",
|
|
239
|
+
"order": 0
|
|
240
|
+
},
|
|
241
|
+
"subsequent_child": {
|
|
242
|
+
"parent": "BRANCH_YES_OR_NO_ID",
|
|
243
|
+
"parentKey": "PREVIOUS_CHILD_ID",
|
|
244
|
+
"order": 1
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"branch_notes": "Branch nodes need BOTH parentKey AND parent (same value). Sibling arrays cross-reference the other branch. Condition node next points to [YES, NO]. Branch node next is a string to the first child when non-empty. CAUTION: Complex branching (>2 if/else in one workflow) can freeze GHL's UI renderer. Use separate exit workflows for nurture sequences instead."
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
"_trigger_patterns": {
|
|
251
|
+
"real_shape": {
|
|
252
|
+
"id": "<UUID>",
|
|
253
|
+
"date_added": "...",
|
|
254
|
+
"deleted": false,
|
|
255
|
+
"belongs_to": "workflow",
|
|
256
|
+
"location_id": "LOCATION_ID",
|
|
257
|
+
"origin_id": "<UUID>",
|
|
258
|
+
"active": true,
|
|
259
|
+
"workflow_id": "WORKFLOW_ID",
|
|
260
|
+
"masterType": "highlevel",
|
|
261
|
+
"name": "Contact Tag",
|
|
262
|
+
"type": "contact_tag",
|
|
263
|
+
"conditions": [
|
|
264
|
+
{
|
|
265
|
+
"operator": "index-of-true",
|
|
266
|
+
"field": "tagsAdded",
|
|
267
|
+
"value": "some-tag",
|
|
268
|
+
"title": "Tag Added",
|
|
269
|
+
"type": "select",
|
|
270
|
+
"id": "tag-added"
|
|
271
|
+
}
|
|
272
|
+
],
|
|
273
|
+
"actions": [
|
|
274
|
+
{
|
|
275
|
+
"workflow_id": "WORKFLOW_ID",
|
|
276
|
+
"type": "add_to_workflow"
|
|
277
|
+
}
|
|
278
|
+
],
|
|
279
|
+
"schedule_config": {},
|
|
280
|
+
"date_updated": "..."
|
|
281
|
+
},
|
|
282
|
+
"customer_reply": {
|
|
283
|
+
"type": "customer_reply",
|
|
284
|
+
"conditions": []
|
|
285
|
+
},
|
|
286
|
+
"appointment": {
|
|
287
|
+
"type": "appointment",
|
|
288
|
+
"conditions": [
|
|
289
|
+
{
|
|
290
|
+
"operator": "eq",
|
|
291
|
+
"field": "calendarId",
|
|
292
|
+
"value": "CALENDAR_ID",
|
|
293
|
+
"title": "Calendar",
|
|
294
|
+
"type": "select",
|
|
295
|
+
"id": "calendar"
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
"contact_tag": {
|
|
300
|
+
"type": "contact_tag",
|
|
301
|
+
"conditions": [
|
|
302
|
+
{
|
|
303
|
+
"operator": "index-of-true",
|
|
304
|
+
"field": "tagsAdded",
|
|
305
|
+
"value": "tag-name",
|
|
306
|
+
"title": "Tag Added",
|
|
307
|
+
"type": "select",
|
|
308
|
+
"id": "tag-added"
|
|
309
|
+
}
|
|
310
|
+
]
|
|
311
|
+
},
|
|
312
|
+
"pipeline_stage_updated": {
|
|
313
|
+
"type": "pipeline_stage_updated",
|
|
314
|
+
"conditions": [
|
|
315
|
+
{
|
|
316
|
+
"operator": "eq",
|
|
317
|
+
"field": "pipelineStageId",
|
|
318
|
+
"value": "STAGE_ID",
|
|
319
|
+
"title": "Pipeline Stage",
|
|
320
|
+
"type": "select",
|
|
321
|
+
"id": "pipeline-stage"
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
},
|
|
325
|
+
"notes": "Workflow GET requests must include ?includeTriggers=true or triggers silently disappear. Each trigger type has type-specific condition fields."
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
"_workflow_design_patterns": {
|
|
329
|
+
"nurture_sequence": "Use linear workflow with stopOnResponse:true. Create separate 'exit workflows' triggered by tags (appointment-booked, do-not-contact) that use remove_from_workflow to pull contacts out. Do NOT use inline if/else gates at every step — this creates too many actions and can freeze GHL.",
|
|
330
|
+
"exit_workflow": "Small 3-4 step workflow: remove_from_workflow → note → tag → notify. Triggered by a tag being added to the contact.",
|
|
331
|
+
"max_actions": "Keep workflows under 40 actions. GHL's UI renderer struggles with larger workflows. Split into multiple connected workflows if needed."
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
{
|
|
2
|
+
"templateName": "Clinic / Med Spa",
|
|
3
|
+
"templateVersion": "1.0.0",
|
|
4
|
+
"description": "Complete GHL sub-account setup for clinics, med spas, and wellness practices. Includes patient pipeline, onboarding workflows, appointment forms, and compliance fields.",
|
|
5
|
+
|
|
6
|
+
"questionnaire": [
|
|
7
|
+
{
|
|
8
|
+
"id": "business_name",
|
|
9
|
+
"question": "What is the name of your clinic or med spa?",
|
|
10
|
+
"type": "text",
|
|
11
|
+
"required": true,
|
|
12
|
+
"placeholder": "e.g. Desert Body Contour"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "owner_name",
|
|
16
|
+
"question": "What is the clinic owner's full name?",
|
|
17
|
+
"type": "text",
|
|
18
|
+
"required": true,
|
|
19
|
+
"placeholder": "e.g. Dr. Jane Smith"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "business_address",
|
|
23
|
+
"question": "Clinic street address?",
|
|
24
|
+
"type": "text",
|
|
25
|
+
"required": true
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "business_city",
|
|
29
|
+
"question": "City?",
|
|
30
|
+
"type": "text",
|
|
31
|
+
"required": true
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "business_state",
|
|
35
|
+
"question": "State?",
|
|
36
|
+
"type": "select",
|
|
37
|
+
"required": true,
|
|
38
|
+
"options": ["AZ", "CA", "CO", "FL", "GA", "ID", "IL", "NV", "NY", "TX", "UT", "WA", "Other"]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "business_zip",
|
|
42
|
+
"question": "ZIP code?",
|
|
43
|
+
"type": "text",
|
|
44
|
+
"required": true
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "business_phone",
|
|
48
|
+
"question": "Main clinic phone number?",
|
|
49
|
+
"type": "phone",
|
|
50
|
+
"required": true
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "business_email",
|
|
54
|
+
"question": "Main support email for patients?",
|
|
55
|
+
"type": "email",
|
|
56
|
+
"required": true
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "business_website",
|
|
60
|
+
"question": "Clinic website URL?",
|
|
61
|
+
"type": "url",
|
|
62
|
+
"required": false
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "clinic_type",
|
|
66
|
+
"question": "What type of practice?",
|
|
67
|
+
"type": "select",
|
|
68
|
+
"required": true,
|
|
69
|
+
"options": ["Med Spa", "Chiropractic", "Wellness/Integrative", "Dental", "Dermatology", "Plastic Surgery", "Acupuncture/Naturopathic", "Physical Therapy", "Other"]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "services",
|
|
73
|
+
"question": "What services do you offer? (select all that apply)",
|
|
74
|
+
"type": "multiselect",
|
|
75
|
+
"required": true,
|
|
76
|
+
"options": ["Body Contouring", "Laser Treatments", "Injectables/Botox", "Facials/Skin Care", "Weight Loss", "Hormone Therapy", "IV Therapy", "Chiropractic Adjustments", "Massage Therapy", "Acupuncture", "Dental Cleanings", "Cosmetic Dentistry", "Physical Therapy", "Other"]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": "appointment_duration",
|
|
80
|
+
"question": "Default appointment duration?",
|
|
81
|
+
"type": "select",
|
|
82
|
+
"required": true,
|
|
83
|
+
"options": ["30 minutes", "45 minutes", "60 minutes", "90 minutes"]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "timezone",
|
|
87
|
+
"question": "What timezone is the clinic in?",
|
|
88
|
+
"type": "select",
|
|
89
|
+
"required": true,
|
|
90
|
+
"options": ["US/Eastern", "US/Central", "US/Mountain", "US/Arizona", "US/Pacific", "US/Hawaii"]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "wants_events",
|
|
94
|
+
"question": "Will you be running launch events or promotions?",
|
|
95
|
+
"type": "boolean",
|
|
96
|
+
"required": true
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "wants_reviews",
|
|
100
|
+
"question": "Do you want automated review request workflows?",
|
|
101
|
+
"type": "boolean",
|
|
102
|
+
"required": true
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
|
|
106
|
+
"location": {
|
|
107
|
+
"name": "{{business_name}}",
|
|
108
|
+
"address": "{{business_address}}",
|
|
109
|
+
"city": "{{business_city}}",
|
|
110
|
+
"state": "{{business_state}}",
|
|
111
|
+
"postalCode": "{{business_zip}}",
|
|
112
|
+
"country": "US",
|
|
113
|
+
"phone": "{{business_phone}}",
|
|
114
|
+
"email": "{{business_email}}",
|
|
115
|
+
"website": "{{business_website}}",
|
|
116
|
+
"timezone": "{{timezone}}"
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
"tags": [
|
|
120
|
+
"new-lead",
|
|
121
|
+
"contacted",
|
|
122
|
+
"appointment-booked",
|
|
123
|
+
"appointment-showed",
|
|
124
|
+
"appointment-no-show",
|
|
125
|
+
"consultation-complete",
|
|
126
|
+
"patient-active",
|
|
127
|
+
"patient-inactive",
|
|
128
|
+
"vip-patient",
|
|
129
|
+
"review-requested",
|
|
130
|
+
"review-received",
|
|
131
|
+
"referral-source",
|
|
132
|
+
"event-registered",
|
|
133
|
+
"event-attended",
|
|
134
|
+
"package-purchased",
|
|
135
|
+
"membership-active",
|
|
136
|
+
"membership-cancelled",
|
|
137
|
+
"reactivation-candidate",
|
|
138
|
+
"do-not-contact",
|
|
139
|
+
"onboarding-complete"
|
|
140
|
+
],
|
|
141
|
+
|
|
142
|
+
"customFields": [
|
|
143
|
+
{ "name": "Clinic Name", "fieldKey": "clinic_name", "dataType": "TEXT" },
|
|
144
|
+
{ "name": "Clinic Owner", "fieldKey": "clinic_owner", "dataType": "TEXT" },
|
|
145
|
+
{ "name": "Primary Service Interest", "fieldKey": "primary_service_interest", "dataType": "TEXT" },
|
|
146
|
+
{ "name": "Patient DOB", "fieldKey": "patient_dob", "dataType": "DATE" },
|
|
147
|
+
{ "name": "Preferred Contact Method", "fieldKey": "preferred_contact_method", "dataType": "TEXT" },
|
|
148
|
+
{ "name": "Insurance Provider", "fieldKey": "insurance_provider", "dataType": "TEXT" },
|
|
149
|
+
{ "name": "Referral Source", "fieldKey": "referral_source", "dataType": "TEXT" },
|
|
150
|
+
{ "name": "Consultation Date", "fieldKey": "consultation_date", "dataType": "DATE" },
|
|
151
|
+
{ "name": "Consultation Notes", "fieldKey": "consultation_notes", "dataType": "LARGE_TEXT" },
|
|
152
|
+
{ "name": "Treatment Plan", "fieldKey": "treatment_plan", "dataType": "LARGE_TEXT" },
|
|
153
|
+
{ "name": "Packages Purchased", "fieldKey": "packages_purchased", "dataType": "TEXT" },
|
|
154
|
+
{ "name": "Total Lifetime Value", "fieldKey": "total_lifetime_value", "dataType": "MONETARY" },
|
|
155
|
+
{ "name": "Last Visit Date", "fieldKey": "last_visit_date", "dataType": "DATE" },
|
|
156
|
+
{ "name": "Next Appointment", "fieldKey": "next_appointment", "dataType": "DATE" },
|
|
157
|
+
{ "name": "Membership Type", "fieldKey": "membership_type", "dataType": "TEXT" },
|
|
158
|
+
{ "name": "Membership Start Date", "fieldKey": "membership_start_date", "dataType": "DATE" },
|
|
159
|
+
{ "name": "Allergies/Contraindications", "fieldKey": "allergies_contraindications", "dataType": "LARGE_TEXT" },
|
|
160
|
+
{ "name": "Emergency Contact", "fieldKey": "emergency_contact", "dataType": "TEXT" },
|
|
161
|
+
{ "name": "Emergency Contact Phone", "fieldKey": "emergency_contact_phone", "dataType": "PHONE" },
|
|
162
|
+
{ "name": "Patient Status", "fieldKey": "patient_status", "dataType": "TEXT" },
|
|
163
|
+
{ "name": "Lead Score", "fieldKey": "lead_score", "dataType": "NUMERICAL" },
|
|
164
|
+
{ "name": "Review Status", "fieldKey": "review_status", "dataType": "TEXT" },
|
|
165
|
+
{ "name": "Event Name", "fieldKey": "event_name", "dataType": "TEXT" },
|
|
166
|
+
{ "name": "Event Date", "fieldKey": "event_date", "dataType": "DATE" },
|
|
167
|
+
{ "name": "Revenue Generated", "fieldKey": "revenue_generated", "dataType": "MONETARY" }
|
|
168
|
+
],
|
|
169
|
+
|
|
170
|
+
"pipelines": [
|
|
171
|
+
{
|
|
172
|
+
"name": "Patient Journey",
|
|
173
|
+
"stages": [
|
|
174
|
+
{ "name": "New Lead", "position": 0 },
|
|
175
|
+
{ "name": "Contacted", "position": 1 },
|
|
176
|
+
{ "name": "Consultation Booked", "position": 2 },
|
|
177
|
+
{ "name": "Consultation Completed", "position": 3 },
|
|
178
|
+
{ "name": "Treatment Plan Presented", "position": 4 },
|
|
179
|
+
{ "name": "Package Purchased", "position": 5 },
|
|
180
|
+
{ "name": "Treatment In Progress", "position": 6 },
|
|
181
|
+
{ "name": "Treatment Complete", "position": 7 },
|
|
182
|
+
{ "name": "Review Requested", "position": 8 },
|
|
183
|
+
{ "name": "Closed — Won", "position": 9 },
|
|
184
|
+
{ "name": "Closed — Lost", "position": 10 }
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
],
|
|
188
|
+
|
|
189
|
+
"calendars": [
|
|
190
|
+
{
|
|
191
|
+
"name": "Consultations",
|
|
192
|
+
"description": "Free initial consultations for new patients",
|
|
193
|
+
"slotDuration": "{{appointment_duration_minutes}}",
|
|
194
|
+
"slotBuffer": 15
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
|
|
198
|
+
"workflows": [
|
|
199
|
+
{
|
|
200
|
+
"name": "New Lead — Instant Response",
|
|
201
|
+
"description": "Sends immediate SMS + email when a new lead comes in. Adds tags and creates opportunity.",
|
|
202
|
+
"actions": [
|
|
203
|
+
{ "name": "Add New Lead Tag", "type": "add_contact_tag", "attributes": { "tags": ["new-lead"] } },
|
|
204
|
+
{ "name": "Send Welcome SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, thanks for your interest in {{business_name}}! We'd love to learn more about your goals. Reply to this text or book a free consultation.", "attachments": [] } },
|
|
205
|
+
{ "name": "Send Welcome Email", "type": "email", "attributes": { "subject": "Welcome to {{business_name}}", "html": "<p style=\"margin:0px;\">Hi {{contact.first_name}},</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">Thank you for reaching out to {{business_name}}. We're excited to help you achieve your goals.</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">Looking forward to meeting you!</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">— {{owner_name}}</p>", "trackingOptions": { "hasTrackingLinks": false, "hasUtmTracking": false, "hasTags": false } } },
|
|
206
|
+
{ "name": "Wait 1 Hour", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "hour", "value": 1, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
207
|
+
{ "name": "Internal Notification", "type": "internal_notification", "attributes": { "type": "notification", "notification": { "body": "New lead: {{contact.first_name}} {{contact.last_name}} — {{contact.phone}} — {{contact.email}}", "title": "New Lead Alert", "userType": "user", "redirectPage": "contact", "type": "send_notification", "selectedUser": "" } } }
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "Appointment Reminder",
|
|
212
|
+
"description": "Sends reminders at 24 hours and 1 hour before appointment.",
|
|
213
|
+
"actions": [
|
|
214
|
+
{ "name": "Send 24hr Reminder SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, this is a friendly reminder about your appointment at {{business_name}} tomorrow. Please reply CONFIRM to confirm or call us at {{business_phone}} to reschedule.", "attachments": [] } },
|
|
215
|
+
{ "name": "Wait 23 Hours", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "hour", "value": 23, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
216
|
+
{ "name": "Send 1hr Reminder SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, your appointment at {{business_name}} is in 1 hour! We look forward to seeing you.", "attachments": [] } }
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"name": "No-Show Follow Up",
|
|
221
|
+
"description": "Follows up with patients who missed their appointment.",
|
|
222
|
+
"actions": [
|
|
223
|
+
{ "name": "Add No-Show Tag", "type": "add_contact_tag", "attributes": { "tags": ["appointment-no-show"] } },
|
|
224
|
+
{ "name": "Wait 30 Minutes", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "minute", "value": 30, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
225
|
+
{ "name": "Send No-Show SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, we missed you at {{business_name}} today! We'd love to reschedule at a time that works for you. Reply to this text or book here.", "attachments": [] } },
|
|
226
|
+
{ "name": "Wait 24 Hours", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "hour", "value": 24, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
227
|
+
{ "name": "Send Follow Up Email", "type": "email", "attributes": { "subject": "We missed you!", "html": "<p style=\"margin:0px;\">Hi {{contact.first_name}},</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">We're sorry we missed you at your appointment today. Life gets busy — no worries!</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">We'd love to reschedule at a time that works better for you.</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">Best,</p><p style=\"margin:0px;\">{{owner_name}}</p><p style=\"margin:0px;\">{{business_name}}</p>", "trackingOptions": { "hasTrackingLinks": false, "hasUtmTracking": false, "hasTags": false } } }
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "Post-Visit Review Request",
|
|
232
|
+
"description": "Requests a Google review 2 hours after an appointment.",
|
|
233
|
+
"condition": "wants_reviews == true",
|
|
234
|
+
"actions": [
|
|
235
|
+
{ "name": "Add Review Requested Tag", "type": "add_contact_tag", "attributes": { "tags": ["review-requested"] } },
|
|
236
|
+
{ "name": "Wait 2 Hours", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "hour", "value": 2, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
237
|
+
{ "name": "Send Review Request SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, thank you for visiting {{business_name}} today! If you had a great experience, we'd really appreciate a quick Google review. It helps others find us!", "attachments": [] } }
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"name": "Reactivation — 90 Day Inactive",
|
|
242
|
+
"description": "Re-engages patients who haven't visited in 90 days.",
|
|
243
|
+
"actions": [
|
|
244
|
+
{ "name": "Add Reactivation Tag", "type": "add_contact_tag", "attributes": { "tags": ["reactivation-candidate"] } },
|
|
245
|
+
{ "name": "Send Reactivation SMS", "type": "sms", "attributes": { "body": "Hi {{contact.first_name}}, it's been a while since your last visit to {{business_name}}. We miss you! Book your next session and get 10% off.", "attachments": [] } },
|
|
246
|
+
{ "name": "Wait 3 Days", "type": "wait", "attributes": { "type": "time", "startAfter": { "type": "day", "value": 3, "when": "after" }, "name": "Wait", "isHybridAction": true, "hybridActionType": "wait", "convertToMultipath": false, "transitions": [] } },
|
|
247
|
+
{ "name": "Send Reactivation Email", "type": "email", "attributes": { "subject": "We miss you, {{contact.first_name}}!", "html": "<p style=\"margin:0px;\">Hi {{contact.first_name}},</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">It's been over 90 days since your last visit to {{business_name}}, and we wanted to check in.</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">As a valued patient, we'd like to offer you 10% off your next treatment. Just mention this email when you book.</p><p style=\"margin:0px;\"><br></p><p style=\"margin:0px;\">See you soon!</p><p style=\"margin:0px;\">{{owner_name}}</p>", "trackingOptions": { "hasTrackingLinks": false, "hasUtmTracking": false, "hasTags": false } } }
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
],
|
|
251
|
+
|
|
252
|
+
"forms": [
|
|
253
|
+
{
|
|
254
|
+
"name": "New Patient Intake",
|
|
255
|
+
"description": "Basic intake form for new patients",
|
|
256
|
+
"fields": [
|
|
257
|
+
{ "label": "First Name", "type": "text", "required": true },
|
|
258
|
+
{ "label": "Last Name", "type": "text", "required": true },
|
|
259
|
+
{ "label": "Email", "type": "email", "required": true },
|
|
260
|
+
{ "label": "Phone", "type": "phone", "required": true },
|
|
261
|
+
{ "label": "Date of Birth", "type": "date", "required": true },
|
|
262
|
+
{ "label": "What service are you interested in?", "type": "select", "required": true, "options": "{{services}}" },
|
|
263
|
+
{ "label": "How did you hear about us?", "type": "select", "required": true, "options": ["Google", "Facebook/Instagram", "Friend/Family Referral", "Doctor Referral", "Drive By", "Event", "Other"] },
|
|
264
|
+
{ "label": "Do you have any allergies or medical conditions we should know about?", "type": "textarea", "required": false },
|
|
265
|
+
{ "label": "Preferred contact method?", "type": "select", "required": true, "options": ["Text", "Email", "Phone Call"] },
|
|
266
|
+
{ "label": "I consent to receive text messages and emails from {{business_name}}", "type": "checkbox", "required": true }
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
}
|