Overview
By the end of this guide you’ll have a voice agent you can talk to right in your browser. You create it with one command, then drop it into a small web page. Browsers handle echo cancellation, so you don’t need headphones, and there’s nothing to install. Prefer to try it first? Talk to an agent without writing any code in the Voice Agent playground.Before you begin
You’ll need:-
An API key. Grab one from your dashboard. The
curlbelow reads it from an environment variable: - A modern browser (Chrome or Edge recommended). That’s the whole client: echo cancellation for free, nothing else to install.
Build your agent
Create an agent, then talk to it in a tiny web page. Four steps, no dependencies.Step 1: Create an agent
id from the response. This is your agent ID:
Step 2: Save the web page
Save this asvoice-agent.html. It’s the whole client: it captures the mic, streams it to your agent, plays the reply, and barges in when you start talking:
Step 3: Open it and talk
Browsers need a secure context for the microphone, so serve the file locally:http://localhost:3000/voice-agent.html, paste your API key and the agent ID from step 1, and click Connect, then start talking. The agent greets you, listens, and replies.
Step 4: Add a tool (optional)
Give the agent the ability to do something. Here it books a meeting with the real Cal.com bookings API. Update the agent with an HTTP tool: you provide the endpoint and a JSON-Schema parameter spec, and AssemblyAI calls it for you whenever the model decides to. Nothing changes in your web page. Replace<YOUR_CAL_API_KEY> with a Cal.com API key and 123 with your event type ID:
Step 5: End the session cleanly
The Stop button in step 2 callsws.close() directly. That leaves the session in a 30-second session.resume grace window on the server, and that window is billable. Send session.end first, wait for session.ended, then close.
Update stop() in voice-agent.html:
session.ended inside your existing ws.onmessage:
pagehide fires on both and is more reliable than beforeunload on mobile Safari:
Send
session.end synchronously inside the pagehide handler. Anything async (like await fetch) will not finish before the socket is torn down.session.end on your shutdown signal (SIGINT, SIGTERM, or your own hangup handler), wait briefly for session.ended, then close the socket. There’s a complete example in the Deploy your agent quickstart. See Unexpected billing after the call ended if your sessions look about 30 seconds longer than the call itself.
Next steps
You just did all three phases at once. Here’s where to go deeper on each:1. Create
Create a reusable agent with one REST call, then update, list, and delete it.
2. Configure
Shape how it sounds and behaves: prompt, voice, greeting, audio, turn detection, keyterms, tools.
3. Deploy
Connect by
agent_id over the API, from a browser, or to a phone number with Twilio.- Add tools: server-side HTTP tools and client-side function tools
- Connect your own LLM: point the agent at an OpenAI-compatible model
- Manage agents (REST): every endpoint, field, and validation rule
- Events reference: every WebSocket event with full payloads
- Troubleshooting: symptom-to-fix table and support logging