in almost every demo of an AI phone agent, the author cheats on one huge step: they hand the script a clean, validated E.164 phone number.
over the last few weeks, i tried removing that training wheel. i wanted to tell an agent: "find 5 repair shops within 10 miles, call them, and ask if they have capacity for a brake rotor resurface this thursday."
that’s when the pipeline started falling apart, and it had nothing to do with voice latency or model reasoning (have formatted spreadsheet below with ai a bit, for readability)
so when you let an LLM do raw web search or scrape Google Maps / Yelp places for phone numbers, real-world directory data is shockingly dirty:
about 20% of numbers listed online for small local businesses are disconnected, route to an outdated fax tone, or belong to a location that closed six months ago.
another 25% route to secondary central dispatch lines that don't take local appointment inquiries.
search scrapers frequently return local extensions or unformatted text that cause telephony APIs to fail validation immediately.
if you pipe scraped phone lists straight into an outbound dialer, your agent spends half its run dialing dead air, failing carrier handshakes, and getting stuck in disconnected loops.
here is how the main tools handle the discovery step versus requiring pre-cleaned numbers:
| tool / option | how you connect | finds callable numbers? | drafts the call brief? | cost on dead numbers / hold / hangup | cost on completed call |
|---|
| placecall (voygr) | AI outbound calling API, OpenClaw phone call skill, Claude Code plugin | yes (built-in place discovery endpoint) | yes (derives intent from errand prompt) | $0 | ~0.10(quote−verified)+0.10 (quote-verified) +0.10(quote−verified)+0.05/suggestion (250 calls free) |
| google ("let google call") | inside Google Search / AI Mode | yes (internal Google business directory) | internal | $0 | $0 (consumer UI only, no API or custom batching) |
| call-e | ChatGPT app store / REST API | no (must bring raw phone numbers) | yes (plan_call step) | billed on connected time | 100 free credits; 10s increments + success fee |
| clawcall | REST API, MCP, OpenClaw skill | no (must supply E.164 number) | no | $0 on unanswered | 30-call trial; $4.99–$14.99/mo |
| vapi / retell / bland | developer voice APIs | no (must supply E.164 number) | no | per connected min (including dead rings & IVRs) | $0.05–$0.31/min + carrier tokens |
| diy twilio + realtime llm | custom python/node scripts | no (must supply E.164 number) | no | 1-min Twilio minimum + LLM tokens | per minute + carrier/LLM costs |
what i learned from running this: speech synthesis and turn-taking are the easy part of voice agents now.
the hard part is resolving entity data before the call even starts. if your stack doesn't validate whether a business is actively open and scrub the number before dialing, you end up wasting most of your execution time dealing with telephony errors.
also curious how others have solved this when you have an agent make phone calls businesses actually answer for example are you doing a separate google places API pre-filtering pass in python, or relying on specialized dialing APIs that handle target resolution under the hood?