Source: I Built A Voice Agent That Calls Every New Lead N8N + Vapi

A walkthrough of an n8n workflow that fires an outbound AI voice call the moment a website form is submitted, qualifies the lead conversationally, and writes the structured results back to a Google Sheet. The build uses n8n for orchestration and Vapi for the voice agent. The same pattern translates directly to a dental-practice intake flow where every new lead receives a callback within 60 seconds — before they shop a competitor.

Key Takeaways

  • The end-to-end loop is six stages: form trigger → phone-number normalization (code node) → branch on validity → Vapi POST /call → polling loop on GET /call/:id → Google Sheet write with structured outputs.
  • Vapi requires two API calls per conversation: one to create the call (returns immediately with a call ID, no transcript), one to get the call (polled until status: ended).
  • A code node — written via a one-shot Claude prompt by pasting incoming JSON — strips parentheses, dashes, country codes, and emits the literal string incorrect format for anything that isn’t a clean 10-digit US number, which short-circuits to a “bad number” sheet row instead of a failed Vapi request.
  • Dynamic prompt variables ({{lead_name}}, {{lead_company_name}}, {{lead_request}}) are substituted at call time via Vapi’s assistantOverrides field, so one Vapi assistant handles every prospect with personalized context.
  • Vapi’s structured outputs (which deprecated the older summary and successEvaluation fields) define the JSON schema the agent extracts during the call — interest, motivation, urgency, past experience, budget, paid intent, status — and are linked per-assistant.
  • Vapi gives 10 free US numbers per account but caps daily outbound calls; production requires importing a Twilio number to scale without limits.
  • Ethical practice in the demo: the agent introduces itself as “an AI agent calling from [company]” on the first turn — a baseline worth keeping for any WEO Marketly deployment.

How It Works

Trigger. A native n8n form submission node stands in for a real website webhook. Captured fields: name, phone, email, company, role, request, company size.

Normalize. A code node receives the form JSON and reformats the phone number to a clean 10-digit string. If the input has too few or too many digits or an unparseable country prefix, it outputs the literal string incorrect format.

Branch. An IF node checks phone === "incorrect format". True branch logs the bad submission to the Google Sheet and stops. False branch proceeds to the Vapi call.

Create call. An HTTP Request node POSTs to https://api.vapi.ai/call with bearer-token auth. Body fields: assistantId, phoneNumberId (the Twilio number), customer.number (prefixed with +1), and assistantOverrides.variableValues containing the dynamic prompt variables. Vapi responds with a call ID and status queued.

Poll. A wait node sleeps 60 seconds (typical conversation length), then a second HTTP Request node GETs /call/:id using the call ID. A limit node trims a Vapi response bug that occasionally returns 26 duplicate items down to the first one. An IF node checks status === "ended" — false branch waits 10 seconds and re-polls; true branch continues.

Voicemail check. A second IF node inspects endedReason. If it equals voicemail, the row is logged with a “callback needed” status. Otherwise the structured output JSON is unpacked from the deeply nested artifacts object and written to the Google Sheet with all qualification fields.

Implementation

Tool/Service: Vapi (voice agent API) + n8n (orchestration) + Twilio (phone number) + Google Sheets (CRM logging).

Setup:

  1. Create a Vapi account, build a “Lead Qualifier” assistant with a system prompt containing identity, style, response guidelines, prospect-information variables in {{double_curly_braces}}, conversation flow, and required topics (interest, motivation, urgency, past experience, budget, paid intent).
  2. In Vapi’s analysis section, define structured outputs as named string/boolean fields and link them to the assistant.
  3. Choose a voice (the demo uses Vapi’s “Elliot” voice) and toggle on the predefined “end call” function.
  4. Import a Twilio phone number into Vapi to bypass the daily outbound cap.
  5. In n8n, build the workflow: form trigger → code node (normalize phone) → IF (validity) → HTTP POST (create call) → wait → HTTP GET (poll) → limit → IF (status ended) → IF (voicemail) → Google Sheets append.

Cost: Not stated explicitly in the source — Vapi pricing is per-minute (combination of LLM tokens, voice synthesis, and telephony). The video does not cite a per-call dollar figure. Free tier includes 10 US numbers with a daily outbound cap; Twilio numbers required to scale. Cost data not available^[inferred].

Integration notes:

  • Bearer-token auth is reusable across both HTTP nodes once saved as a generic credential in n8n.
  • The assistantOverrides.variableValues object is how dynamic context flows in — every prompt variable wrapped in {{}} in the system prompt must have a matching key here.
  • Structured outputs live deep inside artifacts.messages[...].analysis in the GET response — drilling down through the JSON viewer is the only practical way to map fields.
  • Hardcoding +1 in the phone number assumes US-only leads. International deployments need either a country-code form field or a smarter normalizer.
  • The 60-second initial wait is tunable — shorter for low-pickup-rate scenarios, longer for verbose conversations.

Try It

  1. Spin up a Vapi assistant with a system prompt containing 5–7 dynamic variables and 5–7 structured-output fields aligned to the qualifying questions a dental practice asks new leads (urgency, insurance, procedure interest, preferred appointment window).
  2. Import the Twilio number the practice already uses for SMS — calls show the familiar caller ID instead of a random Vapi number.
  3. Build the n8n skeleton as a webhook trigger from the existing intake form (replace the native form node with a Webhook node); pin sample data so you can test the flow without burning real Vapi minutes.
  4. Wire the result row into the practice’s CRM (GoHighLevel, etc.) instead of Google Sheets so the qualified lead lands in the same pipeline as a manually-handled inquiry.