Most founders running booked sales calls are losing 20 to 40% of them to no shows
Run the math on your own pipeline:
40 calls booked, 12 ghost
That's not a scheduling problem, that's a third of your ad spend and SDR hours evaporating after the hard part was already done
The standard fix is email reminders
Email gets opened ~20% of the time WhatsApp gets read 95% most within 3 minutes
Every founder knows this, which is why the second standard fix is "just text them before the call"
Works great until you have five back to back calls and forget one, or the call got moved twice and your reminder references the wrong time
Manual doesn't scale
Email doesn't get read
So I built the third option for a client, into his CRM:
every call booked in Google Calendar automatically triggers WhatsApp reminders to the prospect
Confirmation the day before
Meet link minutes before
Move the call in the calendar and the reminders silently move with it
Cancel it and they cancel themselves
Nobody on the team touches anything. They book calls exactly like they always did
The build is 5 components, and the decisions inside apply to any automation you'll ever run in your business:
1. Reading the calendar (where 90% of DIY versions die)
The obvious way to connect is OAuth, the "Sign in with Google" flow
What nobody tells you: on a personal Gmail, an unverified OAuth app's tokens expire every 7 days
Getting verified means weeks of Google review
This is why most DIY calendar automations die after exactly one week
Not a bug. The token silently expired and nobody noticed until reminders stopped going out
The fix takes 2 minutes and Google doesn't advertise it: skip OAuth entirely
Create a service account in Google Cloud Console
It gets its own email address. Share your calendar with that email, "see all event details" done
Read only scope, so the system physically can't touch the calendar
And when the business migrates from personal Gmail to Workspace, you share the new calendar with the same email and change one config value
Zero rework
The whole auth layer: ~80 lines of code, zero new dependencies
2. The sync worker
Polls the calendar every 5 minutes, 14 days ahead
Expands recurring events, explicitly fetches deleted ones, because a cancellation you don't see is a reminder you send for a call that no longer exists
Meet link auto extracted, nothing to paste anywhere
Key insight: Google keeps the same event ID when a call gets rescheduled
Everything downstream keys on that ID
That single fact is what makes "move the call, reminders follow" possible
3. Matching the attendee to a WhatsApp thread
Attendee email matched against the CRM's contacts: exact match or nothing
Matched → use that contact's WhatsApp thread
No match → never guess
The call shows flagged red in the calendar view so a human fixes the data
A rule worth stealing: a reminder sent to the wrong person is worse than no reminder
Never fuzzy match on names
And the case most builds miss: attendee declined the invite → reminders auto-cancel
A cheerful "see you tomorrow!" to someone who declined your meeting is what makes automation feel like automation
4. Every reminder is a database row
No fire and forget jobs
Every reminder is a row: contact, event, send time, rendered message, status
One constraint makes it bulletproof: one reminder slot per event, per contact, per step
Enforced by the database itself
Sync can run 1,000 times → never a duplicate, never a double send
Call rescheduled → same rows get their time recomputed and message re rendered
If the call moved so close a step's time already passed, it cancels instead of blasting late
Call cancelled → rows flip to cancelled, nothing sends
Operator killed one reminder manually → it stays dead, the sync never resurrects it
The sender itself is dumb on purpose: every 60 seconds, claim approved rows whose time has passed, send with humanized typing delays
All the intelligence lives in the table
The part touching the outside world stays trivially simple, and therefore reliable
5. The cadence (two messages)
T-24h: "Hey {name}! Quick reminder, we have our call tomorrow at 3:00 PM. Looking forward to it 🤝 If anything changes on your end, just let me know"
No link: a link 24 hours early is noise
The message invites a reply, so reschedules surface a day out instead of 5 minutes before
This message is the no show killer
T-10min: "Hey {name}! We're on in about 10 minutes. Here's the link:"
Lands exactly when they're reaching for the link anyway. Helpful, not naggy
Ship the 80%, measure no shows, add the third touch only if afternoon calls still slip
The sequence is a settings page, adding it later takes 10 seconds
Now the part that applies to every AI system that talks to your customers:
How much do you let it act alone?
Full human in the loop makes you the bottleneck for a message that's identical every time
Full autonomy on day one is how you blast 15 people by accident
The answer is autonomy split by confidence:
Exact match English speaking contact → autonomous
Language isn't English → generated but held for one click review
No contact match → never sends, flags a human
Declined → auto-cancelled
Plus a staged rollout with two switches:
Deploy completely dark
Then turn sync on with auto-send off, so every reminder lands as a held draft
You watch real reminders for your real calls pile up with correct names, times, links, and nothing sends without your click
No test environment needed, production simply runs with the safety on
After a few days of clean output, flip auto send
The flip only affects newly created reminders, so turning it on can never trigger a burst of old ones
That trio is reusable in every automation you ship, not just this one
What the client actually got:
a. Prospects get a personal feeling reminder the day before and the link right before every call, from the business's real WhatsApp, automatically
b. The team reschedules in Google Calendar like they always did. Reminders silently follow. No second system to check
c. Wrong data can't cause damage. Unmatched calls flag instead of guessing, non-English drafts wait for a human
Booked calls become held calls, and held calls are the only ones that pay