Voice Agent Confirms Booking Without an Appointment
Gate voice-agent confirmations on successful CRM appointment creation, validate empty payloads, route new contacts correctly, and alert on failed writes.
Voice agent says "you're all set" but no appointment is created
Summary
The agent speaks a confirmation off its own words, not off a real write. Gate every confirmation behind the CRM's created-appointment result, add a validation branch so an empty payload can't crash the booking step, and alert on any failed write. After that, a bad call ends with a spoken correction instead of a false confirmation.
Symptoms
- Callers are told "you're all set" but no appointment record exists.
- The booking workflow throws on the upsert step; the run shows an invalid URL (a relative
/contacts/upsertwith no base URL). - An anonymous or new caller produces a
PUT /contacts/404. - The team hears about the miss from the customer, not from an alert.
Environment
- n8n handling the booking, a marketing CRM for contacts/appointments, and an AI voice agent that collects fields during the call.
Cause
The agent flags fields as confirmed and speaks a confirmation regardless of what the automation returns. When phone, name, city and ZIP arrive blank, validation returns no config, so the upsert step assembles an invalid URL and crashes — but because nothing gated the spoken confirmation, the agent still said the booking was done.
Solution
- Add a "Validation OK?" branch immediately after the parse step.
- On the failure side, return the validation response as text so the agent gets a spoken correction and never reaches a CRM call with empty config.
- On the success side, continue to the existing upsert path unchanged.
- For the update path, change the branch condition from
existstois not emptyso anonymous/new callers are routed to create instead of a 404'd update, and turn on Continue On Fail on the update node as a backstop. - Trigger the confirmation SMS/email only when the CRM returns a created appointment.
- Wire each failure branch to post
failed_booking(caller + error) to the notification dispatcher so the team is alerted instantly.
Example
Booking step, guarded:
Parse Booking Request
└─ Validation OK?
├─ false → Respond Validation Error ={{ JSON.stringify($json) }} (agent re-asks)
└─ true → GHL Upsert Contact → Book Appointment → Handle Result
└─ success:true → send confirmation
└─ any failure → POST dispatcher {outcome:"failed_booking"}
Verification
Re-run the same three-call scenario: an empty/partial payload ends cleanly at the validation response with no crash and no confirmation; a full valid booking creates the appointment and fires the confirmation off the real write; an anonymous caller creates a contact instead of 404ing; and a failed-write alert lands in the test inbox.
Caveats
- Keep edits additive (no node deletions) so production originals stay intact.
- This hardens the automation side only. The agent must actually send the collected values and confirm only on success — that lives in the conversation config, not here.
- Leave test mode on during the build so alerts route to a test inbox, not the client.
Related
- Why a Zapier or GHL webhook can't return a live answer to a voice agent mid-call.
- Preventing double-booking when the platform has no concurrency control.
- Wrong-time booking agent: availability triage, for when the booking is created at the wrong time or the agent offers slots that aren't free.
Was this article helpful? Thanks for your feedback.
Sorry about that. Tell us what was missing and we will improve it.
Keep reading
Related articles
Voice-Agent Alert Emails Missing Post-Call Data
Fix voice-agent alerts missing summaries, recording links, and tags by triggering the workflow after post-call analysis completes.
Read the article Voice AutomationSynchronous Webhook Responses for Voice Agents
Explains why Zapier and GHL webhooks cannot return mid-call data and how an inline endpoint can provide synchronous responses.
Read the article Workflow AutomationPreventing Double-Booking in Concurrent Zapier Workflows
Use atomic storage locks, availability re-checks, and lock expiry to prevent concurrent Zap runs from reserving the same resource.
Read the articleRather have us set it up for you?
Our engineers build these integrations, workflows, and AI features on your stack — documented, tested, and handed over.