Table of Contents
The Problem: Bookings Without Context
Our site offers one free 30-minute AI Strategy Call, reachable from two very different buyer paths: a workflow lane for teams that know what they want automated, and an office lane for organizations that need to decide where AI should operate first. Bookings arrived with a name, a company, and a time, and nothing about which path brought the person in. That left the host prepping cold and analytics unable to say which funnel produced which meetings.
That is the exact class of problem clients bring us, so we fixed ours the way we would fix theirs, and this post documents the architecture that now runs in production on this site.
The Design Decision: Make the Visitor Choose
The tempting fix is silent attribution: carry a URL parameter from the landing page into the form and hope nobody arrives through a side door. We shipped that first, and it worked for visitors who followed the intended paths. It said nothing about everyone else.
The better fix was a product decision, not a tracking one: the booking form now opens with a required question, "What brings you in?", with four options mapping to the two lanes, a managed-operations lane, and an explicit "Not sure yet." Arrivals from a funnel page get their lane preselected; direct arrivals must choose before the form will submit. "Not sure yet" is deliberately a first-class value rather than a missing one, because a prospect who has not chosen a lane is real signal for how the call should open.
One implementation detail worth stealing: on a statically prerendered site, initializing that selector's state from the URL during hydration bakes a mismatch between server HTML and client state that the framework never repaints. The selector initializes empty and syncs from the URL in an effect after mount, which is the general pattern for any URL-driven state on prerendered pages.
One Value, Seven Systems
The chosen value, we call it the route intent, is a closed enum: workflow, office, managed, unsure, or direct. It travels unmodified through every system that touches the booking:
- The form posts it with the booking request.
- The API layer (Lambda behind API Gateway) validates it against the closed set; unknown values are rejected at the boundary rather than coerced downstream.
- DynamoDB stores it on the booking record.
- Analytics receives it as an event parameter, so funnel performance is queryable per lane.
- The calendar invite renders it as a human-readable Funnel line in the event description the host reads before the call.
- The notification email to sales leads with the same line.
- The CRM sync worker polls the booking table and writes a pre-call brief into the CRM: funnel, timing, contact method, the prospect's stated focus, and the meeting link, with the funnel tag appended to the opportunity name so the pipeline board shows lane at a glance.
The rule that makes this architecture boring, in the good sense: one closed vocabulary, validated at the API boundary, with each consumer rendering its own label from the stored value. The client and API each pin the value set explicitly, with comments requiring the two lists to stay synchronized, so a drift fails loudly in review rather than silently in production.
Calendar Routing Without Founder Bottlenecks
The strategy call is sales-owned, so the system books it on the sales calendar, invites only the host and the prospect, and checks availability against the host's calendar alone. The Google Calendar API's event insert supports attendees and notification control directly, so the prospect receives a real calendar invitation rather than a homemade reminder, and the meeting link is generated with the event.
Availability was the subtle part. The listing endpoint and the booking-time check must gate on the same calendars, or the system shows slots it will refuse to book. Our adversarial review caught exactly that divergence: the slot listing was still consulting the founders' calendars while booking checked the sales host. The fix was making both paths resolve calendars from the same per-meeting-type configuration, and the proof was behavioral, run against production: a window where both founders were busy but the host was free now correctly shows open slots, and the host's own busy block correctly removes them, buffers included.
Email Routing as an Org Chart Decision
The email layer encodes who owns what, and getting it wrong quietly misroutes a pipeline. Our rules: the prospect's confirmation sets its reply-to to the sales host, because a reply to a confirmation is almost always a reschedule request and belongs with the person taking the call. The internal notification goes to the sales host directly, because a booking is an assignment rather than an announcement. The shared team inbox rides along as a CC on both messages for awareness, and deliberately appears nowhere on the calendar: visibility should never create calendar dependence.
One operational rule this system taught us to enforce: environment configuration overrides code defaults, so a changed default means checking every layer that can override it, and the only proof is reading the effective value on the running system. That check is now part of the routing verification, not an afterthought.
The Test That Caught a Real Bug
Our working rule for this pipeline: a change is not done until a real booking has run through the production API under a QA identity, with verification at every hop (the database record, the calendar event's description, the email recipients, the CRM brief) and then deletion of every artifact it created.
That habit paid for itself the day it caught a module that referenced a helper it never imported. Static checks passed, because an undefined identifier is a runtime error rather than a syntax error; unit tests passed, because they never executed that module; the failure existed only on the live create path. The end-to-end booking hit it within minutes of deploy, the log named the missing import, and the fix shipped before any prospect ever saw the error. Cheap tests find cheap bugs. Live tests find the ones that cost bookings.
Design Rules We Kept
- Closed enums at boundaries. Attribution values are validated, never free-text, so every downstream consumer can trust the set.
- Machine identifiers freeze; labels evolve. Analytics event names and meeting-type keys never change once shipped; the human-readable wording maps on top and can be improved anytime.
- Every consumer renders, none re-derives. Calendar, email, and CRM all read the stored value and format it locally.
- Notifications never block the transaction. Email and CRM sync failures are isolated and logged so a booking cannot be lost to a notification problem.
- Verify on production, clean up completely. The QA identity books real slots, and the teardown deletes the calendar event without sending cancellations, the database row, and the CRM records, leaving no residue.
This is the same architecture we deliver as custom automation builds: defined boundaries, one source of truth, and verification that exercises the real system. If your own funnel hands your sales team cold calls, the free 30-minute AI Strategy Call is a fitting place to start, and yes, you will be asked what brings you in.
FAQs
Why require the funnel selection instead of tracking it silently? Silent tracking only covers visitors who follow intended paths. Requiring direct arrivals to choose, while preselecting for funnel arrivals, converts "unknown" into an explicit "not sure yet" signal and gives the sales team context on every booking rather than most of them.
Why a closed enum instead of free-form UTM data? UTMs still exist for campaign analytics, but the operational value is validated at the API boundary against a fixed set, so calendar, email, analytics, and CRM consumers can all rely on it without defensive parsing. Unknown inputs are rejected, not stored.
What does the CRM sync add beyond the calendar invite? The pre-call brief in one place: funnel, meeting timing, contact method, the prospect's stated focus and notes, and the meeting link, plus a funnel tag on the opportunity name so the pipeline board shows lane distribution at a glance.
What is the single most reusable lesson? Run one real transaction through production after changing a critical path, verify every hop, and delete what you created. It is the only test class that exercises the same code, configuration, and integrations your customers hit.
---
Sources
- Google, "Events: insert," Calendar API reference. Documents attendee lists and the sendUpdates notification control this system uses to deliver real calendar invitations.
- Amazon Web Services, "SendEmail," Amazon SES API v2 reference. The email API behind the confirmation and notification paths, including simple content with reply-to and CC addressing.
- Anthropic, "Building effective agents". The workflow-versus-agent framing that shaped keeping this pipeline a deterministic workflow with explicit boundaries rather than an agentic system.