Why Route bookAppointment Through n8n Instead of Directly to Cal.com

Vapi constructs the request body using flat key-value pairs. Cal.com v2 API requires a properly nested attendee object. Vapi cannot produce nested JSON from its tool body configuration. Routing through n8n allows a code node to transform the flat structure into the correct nested format before it hits Cal.com.

This was discovered after three failed direct integration attempts.


Why Two Separate n8n Workflows

Workflow 1 fires mid-call via Vapi tool call and must respond within seconds or the call experience breaks. Workflow 2 fires after the prospect completes the post-call modal — it can take time, process enriched data, and send multiple outputs. Combining them would mean the call cannot close until the prospect fills the modal. That is the wrong user experience.


Why Cloudflare Tunnel Over Direct IP

Oracle Cloud IP with port 5678 is accessible internally but creates two problems for production use — no SSL certificate means browser fetch calls from HTTPS-hosted frontends are blocked as mixed content, and direct IP exposure increases attack surface. The Cloudflare tunnel provides an HTTPS endpoint at n8n.anrdigitalstudio.com that routes to the internal port cleanly.


Why Email Collection Uses Natural Speech Not Spelling

Deepgram consistently misidentifies spelled individual letters — A becomes E, B becomes D. Tested across 6 call attempts. The fix was changing the system prompt to ask callers to say the email naturally as one phrase — “john at company dot com” — which Deepgram transcribes with significantly higher accuracy.


Why formattedSlotTime Is Computed in n8n Not the Frontend

The slot time arrives from Cal.com as an ISO 8601 string. It needs to be displayed in human-readable format in Slack, two emails, and the frontend booking confirmed state. Computing the formatted version once in the Validate and Extract node and passing it as a separate field ensures consistency across all outputs without repeated conversion logic.


Biggest Technical Failure and What It Taught

The initial bookAppointment tool was configured to call Cal.com directly with dot-notation property names — attendee.name, attendee.email as literal flat keys. Cal.com returned 400 errors because it expected a nested attendee object. The fix was routing through n8n which builds the correct structure. This was not obvious from the Vapi documentation and required examining the actual Cal.com API error response directly.

Lesson: When two APIs need to talk through an AI tool layer, always verify the exact request structure the receiving API expects before assuming the AI can construct it correctly.