This is an anonymized architecture case study. No client-identifying information is included.
Context
A marketing agency needed a clean lead intake system where:
- Leads submit qualification details via Typeform
- Calls are booked through Calendly
- Contacts and Opportunities are created in GoHighLevel (GHL)
- The team receives enriched booking notifications in Slack
The expectation was simple: every booked call should generate a Slack message containing complete lead context (company, website, ad spend, etc.).
In reality, some Slack messages were “complete” — others showed empty fields.
The Structural Problem
At first glance, the issue looked like a Zapier mapping bug. It wasn’t.
The real problem was architectural:
- Leads could book directly in Calendly without submitting Typeform.
- Some leads used different emails between Typeform and Calendly.
- Not all requested Slack fields existed in the Typeform.
- Both Typeform and Calendly were attempting to influence GHL pipeline stages.
This created two categories of risk:
- Data Inconsistency (Slack enrichment missing)
- Pipeline Stage Conflicts (opportunity overwrites)
Root Cause Analysis
Slack can only display data that:
- Exists in the trigger payload (Calendly booking), or
- Can be reliably looked up from another source (Typeform)
When no matching Typeform submission exists, enrichment fields cannot be populated. This is not a technical failure — it is expected behavior.
Architecture Decision
Instead of “patching mappings”, we redesigned responsibilities:
- Typeform = Qualification & enrichment data (company, website, ad spend, notes)
- Calendly = Booking trigger + sole controller of “Discovery Call Booked” stage
- Zapier = Orchestration layer with conditional enrichment
This separation eliminated pipeline conflicts and clarified the source of truth.
Implementation Details
1. GHL Stability
- Reliable Contact upsert (email-based dedupe)
- Opportunity creation tied exclusively to Calendly booking
- Stage updates centralized to avoid overwrites
2. Conditional Slack Enrichment
- Trigger: Calendly “Invitee Created”
- Lookup: Search Typeform response by email
- If match found → Enriched Slack message
- If no match → Structured fallback Slack message
The system now behaves predictably in both scenarios:
- Typeform → Calendly booking → Full enrichment
- Direct Calendly booking → Booking-only Slack message
3. Access & Governance Fix
During implementation, Zapier connections were marked private, preventing retesting. Access was shared properly to ensure transparent maintenance and future updates.
Results
- End-to-end booking flow stabilized
- No more pipeline stage conflicts
- Predictable Slack notifications with clear fallback logic
- Clear documentation of expected “empty field” scenarios
Key Insight
Automation reliability is not about adding more mappings — it’s about defining ownership of data and controlling where state changes occur.
Many automation issues are not bugs. They are architecture decisions waiting to be clarified.
Stack: Typeform · Calendly · Zapier (Code + Lookup) · GoHighLevel · Slack
If you’re building a multi-entry booking system and want it designed cleanly from the start, feel free to reach out.