Home › GoHighLevel Missed-Call Text-Back
Build teardownGoHighLevel missed-call text-back: the full build — and where the stock feature stops
Turn on the built-in feature. It takes two minutes and it's free. Then read the rest of this page, because the built-in feature sends one text and then stops — and the money is in what happens after the customer replies.
The short version
- The stock GoHighLevel feature auto-texts anyone whose call you miss. Switch it on today.
- It is one outbound message — it doesn't read the reply, answer a question, or book anything.
- The build below adds the missing half: an AI agent that replies, checks your real calendar, books, and escalates.
- It answers on whatever channel the customer used — SMS, webchat or email — and logs every interaction into a weekly owner report.
First: turn on the free one
GoHighLevel ships missed-call text-back natively. It's in Settings → Business Profile, it's a toggle plus a message box, and it fires automatically when a call goes unanswered. If you take calls and you haven't enabled it, stop reading and go do that — the rest of this page is about a bigger build, and none of it is a reason to leave the free thing switched off.
Why it matters at all: a large share of calls to small businesses go unanswered, and for a service business a single job can be worth hundreds. Contact rates collapse within minutes of an enquiry going cold. An automatic "sorry we missed you" recovers some of that on its own.
Where it stops
Four things the stock feature doesn't do, in the order they cost you money:
- It doesn't read the reply. The customer texts "yeah do you do emergency callouts on Sundays?" and that message sits in the inbox until a human opens it. You've automated the apology, not the response.
- It doesn't know your business. One canned message. It can't answer a question about your services, your hours, or your pricing.
- It doesn't book. Even a perfect reply still ends with "let us know a good time" — the slowest possible ending.
- It doesn't know when to stop. No sense of when a conversation needs a human, so nothing gets escalated.
So the goal isn't a better canned message. It's to make the reply itself automatic, informed and able to act.
The build
One inbound workflow does the work, and a second runs the weekly report. Multi-tenant from the start, because the same system serves several businesses without a copy per client.
GHL "Customer Replied" ──▶ Webhook ──▶ Normalize ──▶ Tenant config (Supabase)
│
┌───────────────────┴──────────────┐
missed_call │ │ inbound_message
▼ ▼
GHL SMS text-back AI Agent ──┬─ check_availability
├─ book_appointment
└─ escalate_to_human
│
reply on same channel ──▶ log interaction
- Webhook + Normalize GoHighLevel posts its own native payload shape — the location id, contact id and message body all sit in different places than you'd guess. One Set node remaps it into clean fields so nothing downstream has to know GHL's schema.
- Tenant config One row per client in Supabase: business name, services, hours, FAQ, tone, calendar id, timezone, escalation contact, average ticket value. Everything downstream reads from this row — nothing is hardcoded. Onboarding a new client is a row, not a rebuild.
- Route by event type A missed call goes straight out as the text-back. An inbound message goes to the agent. Two paths, one workflow.
- The AI agent gpt-4o-mini, with a system prompt assembled entirely from that config row, plus the current time in the client's timezone, escalation rules and booking rules. Memory is keyed by contact id, so every customer has their own thread.
- Three tools it can call
check_availabilityreads real free slots from the GHL calendar.book_appointmentcreates the appointment.escalate_to_humanwrites a flagged note on the contact so a person picks it up. - Reply and log The answer goes back through GHL's conversations API on the same channel the customer used, and the exchange is logged for reporting.
- Weekly owner report A scheduled workflow counts conversations and unique leads, pulls appointments from the calendar, multiplies by the client's average ticket value, and emails the owner a plain summary of what the system did that week.
The gotchas
GoHighLevel API versions are not uniform
Calendars and conversations expect one API version header; contacts expect a different one. Send the wrong version and you get errors that read like permission problems. This single detail costs more debugging time than anything else in a GHL build.
The native payload isn't the documented shape
The webhook delivers nested fields — location, contact and message all arrive under their own objects rather than as flat properties. Normalize once at the door and never think about it again.
Agent sub-nodes can't see the webhook
Inside an AI agent's tool calls, expressions that reach back to the webhook node don't resolve — different execution frame. Carry the values you need forward through a Set node and reference them by name instead.
Make the channel a single seam
The inbound channel is mapped to an outbound reply type in exactly one place. That's why adding SMS to a webchat-only build is a one-line change — and why the agent always answers where the customer actually is.
The other half: web-form leads
Missed calls are one source. Web forms are the other, and they deserve the same discipline. The speed-to-lead build I run for that path is worth summarising because the lessons are different:
- Validate at the door. Malformed payloads stop before they create a CRM record or spend a cent on AI.
- Deduplicate on a short window. Same email within ten minutes is a double-submit or a platform retry, not a second lead.
- Capture before you think. Write the lead to the database first, then score it. If the AI step fails, the lead still exists.
- Fail loudly, not silently. If scoring breaks, the error path posts to Slack — "this one needs manual review" — and forces the run to succeed so the captured record survives. An AI outage should never lose a lead.
- Compare numbers as numbers. A score threshold compared as text sorts "10" below "7" and routes your hottest leads to the nurture pile. This is a real bug that shipped once and never again.
What it takes
| Piece | What's needed |
|---|---|
| GoHighLevel | Your existing sub-account, a calendar, and API access |
| Automation layer | n8n (self-hosted is fine and cheap), one workflow per concern |
| AI | OpenAI gpt-4o-mini — cost per conversation is fractions of a cent |
| Config store | Supabase or equivalent, one row per business |
| Build time | A working first version in days, milestone by milestone |
| Ongoing | No per-seat licence. You own the workflows |
Common questions
Should I just use the built-in feature?
Turn it on regardless — it's free and it's better than nothing. Build the rest when the volume of replies sitting unanswered in your inbox starts costing you jobs. That's the actual trigger.
Will it sound like a robot?
Tone is part of the per-client config, and the agent's knowledge comes from your own services, hours and FAQ rather than generic filler. The bigger safeguard is honesty: it's instructed to escalate rather than invent an answer, which is what actually makes customers trust it.
Can it book into my GoHighLevel calendar directly?
Yes — it reads genuine free slots from the calendar and creates the appointment through the API. It doesn't offer a time it hasn't verified.
What if it gets something wrong?
It escalates by writing a flagged note on the contact, so a human sees it in GoHighLevel where they already work. Every conversation is logged, so you can read exactly what was said.
Does this work for an agency with multiple clients?
That's how it's built. Configuration is one row per sub-account — business name, services, hours, tone, calendar, escalation contact. Adding a client is adding a row.
Losing leads between the missed call and the callback?
Tell me how enquiries reach you now and what usually happens to them. I'll map what could be automated and what it would cost — no charge, no call required.