A follow-up check for outdoor-living projects

Prepared forHillman Outdoor Living
DataExample data. Not connected to your account.
Example snapshotSep 22, 3:55 pm Central. All eight data sources are represented as complete.

A fictional Fort Worth builder’s GoHighLevel sub-account. Deadlines, stages and templates are set for the example.

GHL
runs the follow-up and the deadline alerts.
The check
flags missing or inconsistent outcomes.
Claude
helps explain them and prepare changes for your review.
Needs a fix

Patio inquiry: no first reply found

What was expected

Within 60 minutes of the project inquiry form: a text or email from a person, the expected automatic reply, or a call that reached her.

What was found

Dana Whitfield sent the form at Tue 9:12 am, and an opportunity opened seconds later. No reply to her project inquiry was found in the data read at Tue 3:55 pm. The newsletter sent at 11:00 am does not answer that inquiry.

1 h
5 h 42 min past due, no reply
Tue 9:12 amInquiry form
Tue 10:12 amReply due
Tue 3:55 pmData read
  1. ATue 9:12 amInquiry form
  2. BTue 10:12 amReply due
  3. CTue 3:55 pmData read
What this does not tell us

Why. The speed-to-lead workflow may not have started, may have stopped at a condition, or may listen to another form. The public endpoints checked here do not show who entered a workflow; GHL does.

What to check in GHL

Open her conversation and check for a response to this inquiry, including a logged call. Open the speed-to-lead workflow and search Enrollment History for her. Not there: look at the trigger, which form it listens to and what its filters require. There: open Execution Logs and see the step where she stopped.

Native fix to test

For a human text or email reply: the Wait action’s “A user to reply”, timeout at 60 minutes, and a Send Internal Notification on the timeout branch. It resolves when your team’s reply is delivered. Automated acknowledgements and calls need their own evidence; they are not assumed to satisfy it. HighLevel suggests this wait after the contact has messaged in, so test it on a form inquiry before relying on it.

Start it from something that does not depend on the workflow being watched, and count the deadline from the form. Watching an opportunity that was created only covers the inquiries that got that far.

Execution-error notifications do not establish that every expected inquiry entered the workflow, and Stale Opportunities counts in whole days. GHL also flags configuration errors before a workflow is published: worth a look during the review.

Needs a fix

Consultation confirmed with a blank name

What was expected

The confirmation text opens with the client’s first name.

What was found

The text stored for Marcus Reyes’s confirmation, sent Mon 3:06 pm:

Hi , your home consultation is set for Thursday at 10:00 am. Reply C to confirm.

The contact record has the full name in Last Name and an empty First Name. Check the form mapping and any later updates. Another open inquiry has no first name. If it receives this template unchanged, the greeting will also be blank.

What this does not tell us

How a misspelled field would render: that is not documented, so it gets tested. An empty field is documented to render as a blank, which matches the stored text.

What to check in GHL

On the contact, compare the first and last name fields. On the inquiry form, see whether the name is one field or two. In the confirmation workflow, open the text action and note every field it uses.

Native fix to test

Before the text, an If/Else branch on First Name: when it is empty, send a version that opens with “Hello,”. For something the message cannot do without, like the appointment time, stop and create a task for the coordinator instead. Test with one contact that has no first name.

Needs a fix

Booked, and still asked to book

What was expected

Once a home consultation is booked, the follow-up stops asking for one.

What was found

Priya Natarajan booked at Mon 3:40 pm for Thu 1:00 pm. At Tue 10:00 am an automated text went out:

Still planning your outdoor kitchen? Book your free home consultation: example.com/consult

18 h 20 min after booking
2 days 3 hours
Mon 3:40 pmConsultation booked
Tue 10:00 amAsked to book
Thu 1:00 pmConsultation
  1. AMon 3:40 pmConsultation booked
  2. BTue 10:00 amAsked to book
  3. CThu 1:00 pmConsultation
What this does not tell us

The example shows a booking request sent after the consultation was booked. In a real account, confirm the appointment status at the time and that both relate to the same project. Which workflow sent it: GHL shows that.

What to check in GHL

In Conversations, open this message’s details and follow the Workflow link: it opens the exact execution that sent it. In that workflow, look for what should end it once a consultation is booked.

Native fix to test

A Goal Event on Appointment Status placed after the last booking request: once she books, she jumps to the goal and skips the remaining asks. Or a Remove from Workflow step in the booking workflow. Test: book a consultation for a test contact who is in the follow-up and check that no booking request follows.

Set aside, correctly

16 days in Design proposal sent

What the rule says

An opportunity in Design proposal sent for more than 10 days gets a look.

Why it is left alone

Renee Castillo wrote on Sep 8:

We're traveling until Oct 6. Can we pick the design back up when we're home?

The coordinator answered and recorded the wait on the contact (a “hold until” field in this example). Flagging it would teach the team to skim past the report.

Wait agreed with the client
Sep 6Proposal sent
Sep 8Asks to wait
Sep 22Data read
Oct 6Back on the list
  1. ASep 6Proposal sent
  2. BSep 8Asks to wait
  3. CSep 22Data read
  4. DOct 6Back on the list
Not to scale.

Suggested focus for your 60-minute review

  1. Trace one inquiry through intake and follow-up.
  2. Inspect the branches together.
  3. Rank the changes and the tests.

Start with your existing Claude connection; no new integration is needed for the screen-share review.

Proposed division of work

GHLRules to configure and test in your account: sending, waiting, conditions, stopping a follow-up that no longer applies, deadline alerts.
The deterministic checkMatches the data it can read and states when an expected result is missing, on a defined scope. It says when it could not read enough to conclude.
ClaudeExplains the exceptions and prepares changes or tests for your review, from what your connection can access.
The owner, or someone he namesApproves any change to a workflow, a tag or a contact before it happens.

What the endpoints do not show

The public endpoints checked here do not expose triggers, branches, waits or who entered which workflow: they list workflows by name and status. The logic gets reviewed together, inside GHL.

A scheduled check is not an alert

A scheduled check only sees a missed reply when it runs: in this example, read at 3:55 pm, almost six hours after the deadline. Speed to lead needs its own alert inside GHL, at the deadline itself.

On a real account

Possible with a Private Integration token whose read-only scopes you choose, after we agree on the scope, rotated or deleted when it is no longer needed. Any write, even a tag, can fire a workflow, so write access stays off. None of this is needed to start.

Other checks on this run 6 to look at
Ortiz

Open inquiry with no first name on file. When a consultation is booked, the confirmation text would open with a blank. Fix the record or add the If/Else branch described above.

Kevin Lott

18 days in Estimate sent, where the example allows 14. Time in stage to check: the client may simply be deciding. Look for the agreed next step on the opportunity.

Native going forward: a Stale Opportunities trigger on this stage. It does not look back at opportunities already waiting, which is where a one-off check helps.

Frank Delgado

Home consultation Wed 2:00 pm, booked Mon 9:10 am. The calendar has an active text reminder 24 hours before. No text was found near Tue 2:00 pm.

A clue, not proof: the export does not document which source a native reminder carries. Check the contact’s conversation, then the calendar’s notification settings.

Site measurement calendar

No active reminder to the contact is configured on this calendar.

Check workflows, manual reminders and any other connected sending system. Worth a look, not a verdict.

Ruth Ambrose

5 automated messages within 24 hours, above the 3 set for the example. Frequency to check.

A count does not prove two workflows collide. Open each message’s details to see which workflow sent it.

Review request after completion

Listed as needed for this example, and its status reads “draft”, not “published”.

A draft is often deliberate, so only workflows named as needed are compared. “Published” is also not proof that it works.

Set aside on purpose 4 excluded by a rule, 4 correctly not flagged
Wes Pruitt

Opted out of text, email and calls: no automated reply is expected. A person decides.

Sam Ortega

Asked to book again after cancelling: that is the right message.

Appointment cancelled: no reminder expected.

Renee Castillo

Wait asked for by the client and recorded.

Hannah Cole

Booked after the reminder was due: no reminder expected.

Glen Harber

Added Tue 8:00 am by an import, with no inquiry form. A recent “date added” is not an inquiry.

Tyler Moss

A client since 2023 who sent the warranty request form Tue 10:15 am. A service request is not a sales inquiry.

Bill Keene

A client since 2024 with a new inquiry Tue 11:30 am: counted as an inquiry despite the old “date added”, and answered within 1 minute.

Alicia Brandt

Answered by a call from a person that reached her (Tue 1:20 pm). Our rule: a call counts only when the contact was reached, not a missed call or voicemail.

When the check cannot conclude try it

Tick what goes wrong with the collection. The same functions as above run again in your browser on the example data.

Complete run. Exceptions listed with their next check.
  • 9 exceptions on 7 contacts, 4 contacts excluded by a rule, 0 checks that could not conclude.
References each check relies on30 references: 25 documented, 3 not documented, 2 conflicting, none tested live30 references, none tested live
BehaviourStatusHow the check uses itSource
GET /conversations/messages/export
Without a channel parameter, the message export returns every non-email type, including activity entries. Email needs channel=Email.
documentedEmail is read in its own pass. If that pass is missing, no absence of reply is concluded for a contact who allows email.Marketplace: Export messages by location ID
Spec: apps/conversations.json
GET /conversations/messages/export
The export cursor is valid for two minutes from the last request.
documentedAn expired cursor marks the pass as partial; nothing is concluded from a partial pass.Marketplace: Export messages by location ID
GET /conversations/messages/export
Group chat and SMS review request types are not supported by the export.
documentedReview requests are never counted as replies, and their absence is never read as a failure.Marketplace: Export messages by location ID
GET /conversations/messages/:id
A message carries source (workflow, bulk_actions, campaign, api, app), status (including scheduled, pending, failed, undelivered) and direction. Body is optional.
documentedFailed, undelivered, scheduled and pending messages are not replies. Bulk and campaign sends are not replies. A missing body is never read as a clean message.Marketplace: Get message by message id
Spec: apps/conversations.json
Version header
Version header for conversations and calendars routes: the spec lists 2021-04-15, the marketplace page lists 2021-07-28 and marks that documentation as no longer actively maintained (v3 is current; the current Get Workflow page also lists v3). Contacts, opportunities, forms and workflows list 2021-07-28 in both. Version 2021-04-15 or 2021-07-28.
conflictVersions here describe the documentation read, not a validated contract. The version and a raw response get checked on the first authorised read.Spec: apps/conversations.json
Spec: apps/calendars.json

Marketplace page, version banner
GET /forms/submissions
Form submissions can be listed by location, form and date range. Version 2021-07-28.
documentedThe list of expected inquiries comes from here (the normal entry), never from the workflow being watched.Spec: apps/forms.json
GET /contacts/:contactId
A contact has dateAdded, source, tags, dnd and dndSettings. Version 2021-07-28.
documenteddateAdded is not used to define an inquiry: imports, returning clients and recruiting all break it. DND decides which channels count.Spec: apps/contacts.json
GET /opportunities/:id, /opportunities/search
An opportunity has lastStageChangeAt, distinct from lastStatusChangeAt and updatedAt. Version 2021-07-28.
documentedTime in stage is measured from lastStageChangeAt, then weighed against any wait agreed with the client.Spec: apps/opportunities.json
GET /calendars/events
Calendar events carry appointmentStatus (new, confirmed, cancelled, showed, noshow, invalid on appointment objects; the event list types it as a free string), startTime, dateAdded, dateUpdated.
documentedCancelled appointments are set aside. A booking after the reminder was due is set aside.Marketplace: Get Calendar Events
Spec: apps/calendars.json
GET /calendars/:calendarId/notifications
A calendar's notifications list type (reminder, confirmation...), channel, receiver, isActive and beforeTime offsets.
documentedA reminder is expected only where the calendar has an active contact reminder, at its configured offset.Marketplace: Get notifications
Spec: apps/calendars.json
Which source value a native calendar reminder carries in the message export.not documentedAny outbound message on the reminder's channel near the due time is accepted as a match. A missing match is a clue, not proof.No official source found
GET /workflows/
The workflow list exposes id, name, status, version, createdAt, updatedAt. No triggers, branches, delays or actions. Version 2021-07-28.
documentedOnly a named, expected workflow is compared with its expected status. Workflow logic is reviewed in GHL itself.Spec: apps/workflows.json
GET /workflows/
The status values of a workflow. The spec gives only "draft" as an example; "published" and "paused" are not documented.
not documentedThe expected status is a setting of the check ("published" in the example), to confirm against a real response. No paused check exists.Spec: apps/workflows.json
POST / DELETE /contacts/:contactId/workflow/:workflowId
The API can add a contact to a workflow and remove it. It offers no read of a contact's enrolments. Version 2021-07-28.
documentedThe check never claims a contact did or did not enter a workflow. It states that an expected result is missing.Spec: apps/contacts.json
The native Stale Opportunities trigger fires after a duration in a stage, set in whole days. It does not work retroactively.documentedTime in stage is a secondary check; the native trigger is the recommended fix going forward.Help: Workflow Trigger, Stale Opportunities (27/04/2026)
Workflow error emails are off by default and send at most one email every 24 hours. This documentation (phase 1, 2024) lists webhooks, premium actions, and Facebook and Instagram actions; it does not list texts or emails.documentedExecution-error notifications do not establish that every expected inquiry entered the workflow. Worth turning on for what they cover.Help: Error Notifications in workflows (11/09/2024)
A tag added or removed by hand or by a workflow, or added by a third-party integration such as Zapier or by a CSV import, can fire a workflow with the Contact Tag trigger.documentedWhy write access is restricted by token scopes, not by a promise to only touch tags.Help: Workflow Trigger, Contact Tag (09/06/2025)
A merge field with no data is replaced with a blank. There is no fallback value.documentedA blank greeting in a sent message is read as a defect; a missing first name before a send is a risk.Help: Overview of Merge Fields (01/09/2026)
How a misspelled or unknown merge field renders.not documentedNot coded. To test in the account with one message to an internal contact.No official source found
If/Else routes contacts by conditions; when a value is unavailable the field may be empty and the workflow keeps running.documentedThe prevention for a blank name is a condition placed before the send, not a later scan.Help: Workflow Action, If/Else (01/09/2026)
A Goal Event can watch Appointment Status. When the goal is met, the contact jumps to the Goal Event step and skips the steps before it. End this workflow, Continue anyway and Wait until the goal is met set what happens to a contact who reaches the step without meeting the goal.documentedThe native fix proposed for a follow-up that keeps asking a booked client to book: the goal placed after the last booking request.Help: Workflow Action, Goal Event (08/07/2026)
The Wait action has “A user to reply”: it holds the contact until a team member replies on a chosen channel, with an optional timeout whose branch is used to escalate. It resolves when the reply is delivered. The article suggests placing it after the contact has messaged in.documentedThe native option proposed for a missed first reply, for human text or email replies only. To test on a form inquiry.Help: Workflow Action, Wait (07/09/2026)
The User Replied trigger fires on messages a user sends from the conversation view, once delivered. Messages sent by workflow actions or Conversation AI do not fire it.documentedWhy automated acknowledgements are not assumed to satisfy a human-reply rule.Help: Workflow Trigger, User Replied (10/07/2026)
Workflows highlight configuration errors (missing settings in actions, invalid If/Else or Wait configurations) before publishing.documentedMentioned as a native layer to look at during the review; it is not a no-reply alert.Help: Highlighting and Resolving Errors in a Workflow (15/09/2026)
A call message carries meta.callStatus: pending, completed, answered, busy, no-answer, failed, canceled or voicemail.documentedOur rule: a call counts as a reply only when completed or answered. A missed call or voicemail is an attempt.Spec: apps/conversations.json
messageType: the spec's enum lists TYPE_SMS, TYPE_EMAIL, TYPE_CALL; the example of the same property shows SMS.conflictBoth forms are accepted. To confirm on a real response.Spec: apps/conversations.json
The Remove from Workflow action takes a contact out of chosen workflows.documentedAlternative fix: the booking workflow removes the contact from the nurture.Help: Workflow Action, Remove from Workflow (08/04/2025)
From a message's details in Conversations, a link opens the exact workflow execution that sent it.documentedThe first place to look for any message a finding points to.Help: Execution Logs and Enrollment History (15/04/2026)
Private Integration tokens carry the scopes the owner chooses and stay valid until rotated.documentedConnecting a real account would use a read-only token chosen by the owner, rotated or deleted when no longer needed.Help: Private Integrations (24/06/2026)
HighLevel's MCP server discovers, describes and executes API operations under the connection's scopes.documentedClaude can read and explain this check's report. It does not run the check's tested functions through MCP.Marketplace: MCP Server

An inventory of references, not behaviours verified in an integration. Read on Sep 25, 2026 in HighLevel’s API specification (commit 0af86a4), marketplace documentation and help center; versions describe that documentation. Nothing on this page has been run against a real HighLevel account.