Building Voice AI Assistants with VAPI: From Setup to Production
A practical guide to building voice AI assistants using VAPI, including webhook handlers, tool integration, and connecting to LLMs.
March 7, 2026 · 5 min · 1039 words · Rob Washington
Table of Contents
Voice AI has matured significantly. VAPI makes it straightforward to build voice assistants that can actually do things—not just chat, but call APIs, look up data, and take actions.
{"model":{"tools":[{"type":"function","function":{"name":"get_weather","description":"Get current weather for a location","parameters":{"type":"object","properties":{"location":{"type":"string"}},"required":["location"]}}},{"type":"function","function":{"name":"check_email","description":"Check for unread emails","parameters":{"type":"object","properties":{}}}}]}}
fromfastapiimportFastAPIimporthttpxapp=FastAPI()@app.post("/vapi/webhook")asyncdefvapi_webhook(request:dict):message=request.get("message",{})msg_type=message.get("type")ifmsg_type=="tool-calls":tool_calls=message.get("toolCalls",[])results=[]fortcintool_calls:func=tc.get("function",{})name=func.get("name")args=json.loads(func.get("arguments","{}"))result=awaithandle_tool(name,args)results.append({"toolCallId":tc.get("id"),"result":json.dumps(result)})return{"results":results}return{"status":"ok"}asyncdefhandle_tool(name:str,args:dict)->dict:ifname=="get_weather":location=args.get("location","New York")# Call weather APIasyncwithhttpx.AsyncClient()asclient:resp=awaitclient.get(f"https://api.weather.com/...")data=resp.json()return{"response":f"Currently {data['temp']}°F in {location}"}elifname=="check_email":# Check email via IMAP or APIcount=awaitget_unread_count()return{"response":f"You have {count} unread emails"}return{"response":"Unknown tool"}
importhmacimporthashlibdefverify_vapi_signature(payload:bytes,signature:str,secret:str)->bool:expected=hmac.new(secret.encode(),payload,hashlib.sha256).hexdigest()returnhmac.compare_digest(expected,signature)@app.post("/vapi/webhook")asyncdefwebhook(request:Request):body=awaitrequest.body()signature=request.headers.get("x-vapi-signature","")ifnotverify_vapi_signature(body,signature,WEBHOOK_SECRET):raiseHTTPException(status_code=401)# Process request...
// OpenAI
{"provider":"openai","model":"gpt-4o"}// Anthropic (requires API key in VAPI credentials)
{"provider":"anthropic","model":"claude-3-5-sonnet-20241022"}// Custom (route to your own endpoint)
{"provider":"custom-llm","url":"https://your-llm.com/v1/chat"}
Note: Using Anthropic requires adding your API key to VAPI’s credential settings—it’s not automatic.
@app.post("/vapi/webhook")asyncdefwebhook(request:dict):msg_type=request.get("message",{}).get("type")# Inject customer data at call startifmsg_type=="assistant-request":caller=request.get("call",{}).get("customer",{})phone=caller.get("number","")# Look up customercustomer=awaitget_customer_by_phone(phone)return{"assistant":{"model":{"messages":[{"role":"system","content":f"Customer: {customer['name']}. Account status: {customer['status']}."}]}}}
asyncdefhandle_tool(name:str,args:dict)->dict:try:result=awaitexecute_tool(name,args)return{"response":result}exceptTimeoutError:return{"response":"That's taking longer than expected. Let me try again."}exceptExceptionase:logger.error(f"Tool {name} failed: {e}")return{"response":"I wasn't able to complete that action."}
VAPI provides a web-based testing interface, but you can also test programmatically:
1
2
3
4
5
6
7
8
9
# Start a test callresponse=requests.post("https://api.vapi.ai/call/web",headers={"Authorization":f"Bearer {VAPI_API_KEY}"},json={"assistantId":"your-assistant-id"})call_url=response.json()["webCallUrl"]print(f"Test at: {call_url}")
Webhook reliability — Use a queue for async tool execution
Latency — Keep tool responses under 3 seconds
Error messages — Make them conversational, not technical
Logging — Record all interactions for debugging
Rate limiting — Protect against abuse
Fallbacks — Have defaults when tools fail
Voice AI is no longer science fiction. With VAPI handling the voice pipeline and your webhook handling the logic, you can build surprisingly capable voice assistants in a weekend.
The key insight: treat tools like API endpoints. If you can build a REST API, you can build a voice assistant.
📬 Get the Newsletter
Weekly insights on DevOps, automation, and CLI mastery. No spam, unsubscribe anytime.