What Broke When I Integrated Booking Tools With Calendars
OAuth Token Weirdness When Connecting Google Calendar
If you’re using something like Calendly, Zoho Bookings, or literally any appointment plug-in that promises “2-click” Google Calendar integration, know this: the second click is hiding an inconvenient secret — expiring tokens that don’t always refresh when you expect.
There was a client setup where the booking system silently lost sync with Google Calendar for roughly a week. No visible errors. No notifications. Bookings kept getting created, but they never showed on the client’s calendar. Turns out, the token had expired and the refresh mechanism was failing — quietly. The booking system assumed the token was still good, while Google’s API was just 401’ing in the background.
What solved it? Manually revoking app access in the user’s Google account and then re-authorizing. Yeah. Not ideal. Worse? The system continued to say “connected” the whole time. Google thinks this is a feature.
Here’s the thing that finally gave it away:
{“error”:”invalid_grant”,”error_description”:”Token has been expired or revoked.”}
If you get something like that from /token
or /calendars/primary/events
, just rip off the integration and redo it from scratch. The system’s not fixing itself.
Bookings Created Outside Availability Windows
This bug drove me nuts. A custom booking platform I helped build would occasionally let users book outside the defined availability ranges. Not just five or ten minutes out—like, midnight on a Sunday when the host had zero open slots. I triple-checked time zones, business hours, even buffer logic.
Cause? Partial-day overrides. Turns out, editing a day’s availability (e.g., giving yourself Tuesday off) doesn’t fully remove inherited settings in some systems. In our example, the default availability got cached server-side, and unless the override explicitly set an empty time range, the original range might still bleed through.
Fix was adding a nil time-block object for stale overrides during sync rehydration. If it’s unclear to your booking engine what “unavailable” means (absence of slots vs explicit denial), this will bite you sooner or later.
Apple Calendar Subscriptions Don’t Respect Recurring Events Properly
You’d think Apple Calendar would be the Switzerland of ICS parsing — but try pushing a recurring weekly event feed to it. If the ICS file has non-standard RRULE formats (which a surprising number of SaaS scheduling tools use), you’ll see odd gaps or phantom duplicates in the Apple Calendar view.
I had a session coach who used Apple Calendar exclusively. Every Tuesday session showed up twice, once at 10 AM and again at… Tuesday, 10 AM. Why? Their app had added an iCal feed but also imported the events via their Apple ID-integrated email, so ICS attachments got parsed twice.
What helped:
- Sticking to absolutely minimal ICS syntax: DTSTART, DTEND, and no BYSETPOS or weird RRULE series
- Renaming the .ics feed filename — bizarrely, a few iOS versions cached the feed path
- Disabling automatic event parsing in iOS mail settings
This only happened with Apple Calendar, and only when the .ics file came from a third-party host. Google Calendar didn’t care. Outlook grumbled via email at least, which was something.
The Zapier Lag Lie
If you’re piping things like new calendar events → CRM via Zapier, don’t trust the “trigger every 15 minutes” line. That interval is almost always longer than it claims, especially on free or core-tier plans. I’ve seen delays of over an hour on Medium usage accounts — and no visible throttle warnings.
In a case where an online consultant was triggering onboarding workflows on event creation, the delay caused welcome emails to go out after the meeting had ended. Scheduling follow-ups got chaotic fast.
Ironically, adding a buffer delay step in the Zap (wait 2 minutes > send email) helped things sync more accurately. Probably because it forced the Zap run onto a more reliable queue than the default timing.
Undocumented behavior:
If the Zap trigger is looking for booked-slots that match complex filter logic (e.g., finding calendar events with keywords), and nothing matches in a window, Zapier may deprioritize your trigger polls to “light usage” tiers, slowing down other Zaps too. This isn’t clearly documented, but it absolutely showed up in logs and correlated with delays.
Timezone Offsets vs DST Transitions – Who Even Wins
This one always feels like a time vortex. Most people assume if they’ve marked their Google Calendar as “Eastern Time” or “Europe/London”, their appointments will auto-adjust correctly during daylight saving shifts.
Not always. Some platforms store datetime stamps as static timestamps in UTC, and only show the label “Europe/London” for UI display. Booking slots then remain locked to pre-DST hours. So if someone books 2 PM London time in March, good luck aligning it with your actual 2 PM in April.
I’ve logged a booking where the displayed time was “2:00 PM BST”, but the back-end actually saved UTC+0, not +1. This meant the client appeared to have a booking at 3 PM their local time, even though the platform said 2 PM.
Don’t trust snapshots of formatted times. Always check the datetime + full timezone object in API payloads.
Multi-Calendar Sync: Only One of Them Wins
Connecting both work and personal Google Calendars to the same booking system? Yeah — one of them is getting stomped.
In every system I’ve tested (including Acuity, Calendly, and custom OAuth setups), the behavior goes something like this:
- First calendar added holds write priority
- Subsequent calendars may have read access but often NOT write
- Some tools parallel-write events, creating double-booking conflicts
Handled a case where a therapist had sync setup with both her practice calendar and her Google Workspace calendar. 70% of events were duplicated, with mismatched attendees. Worse, her main booking tool marked them as busy, so clients couldn’t book actual open hours.
If using multiple calendars, test with:
- One write-enabled calendar only
- Turn off sync for read-only layers
- Disable all-app notifications (some apps fire calendar invites from all synced layers)
Google needs better tooling here, but until then, assume your calendar integration is a data race unless you narrate priorities explicitly.
Reschedule Logic Can Break Notification Chains
Some systems treat a reschedule as “delete + create”. Others patch the event. A few do both, depending on platform.
In one client flow, rescheduling a call via the embedded booking link triggered a new event, but skipped past the original confirmation pipeline — so no pre-call email ever went out. The Zapier logic was listening for newly booked appointments, not rescheduled ones.
The easiest fix? Adding an event ID tracker. Anytime an event was changed instead of canceled+recreated, the system now updates a table entry AND flags it as a touchpoint requiring re-touched workflows. I had to dig three levels deep into webhook payloads to even confirm this was the issue.
Fun fact: Calendly doesn’t actually send a cancellation webhook when an appointment is rescheduled. That’s not a bug. It’s totally intentional. Sane? Debatable.
Google Meet Auto-Inserts Conflicts Into Events
Let’s say your appointment system integrates with Google Calendar and creates the events using the Calendar API. If you include conferenceData.version
in your API call, Google will probably attach a Meet link.
Now imagine your client also uses Zoom auto-inclusion. Congrats — every booking has two conflicting video links.
There was a case where a client sales team was showing up in Zoom rooms while their leads were sitting in Google Meet. Entire sales funnel dunked for a week simply because no one thought to disable Google’s implicit Meet-injection.
Cleanest tweak? Remove this line from your event creation logic:
"conferenceData": { "createRequest": { "requestId": "xyz" } }
Also go to Google Calendar > Settings and under Event settings, uncheck “Automatically add Google Meet video conferences to events I create. You’d think the API would respect this, but nope. It defaults to adding Meet unless told not to — logic override, not preference-driven.
Most booking tools don’t expose this config directly. You’ll need to manually patch the API template or work with whatever provider you’re using to disable it at the account level.