Talk to your own voice agent in the browser in about 5 minutes. No phone number needed.
Talk to your own voice agent in the browser in about 5 minutes. No phone
number needed. Unpod hosts the speech service - microphone capture,
speech-to-text, text-to-speech, and the audio bridge. You write the agent’s
brain and run a small browser UI on your machine to speak with it.This is the fastest way to hear your agent. When you want a real phone call,
follow Make Your First Phone Call afterwards.For production, follow the steps below and use the deploy checklist for the
runner-specific settings.
Unpod
Phone numbers, STT, TTS, routing, call control
Your App
Agent brain, tools, prompts, business logic
Production
Public runner, secrets, scaling, shutdown, observability
ANTHROPIC_API_KEY — your own key from console.anthropic.com → API Keys. Use any provider you want — OpenAI, Gemini, etc. The variable name is just an example.
Create a .env file in your project root and add the API keys:
Local Dev
Production
UNPOD_API_KEY="sk_..."ANTHROPIC_API_KEY="sk-ant-..."# Local dev overrides — remove for productionUNPOD_SERVICE_BASE_URL=http://localhost:8000/platformUNPOD_ORCHESTRATOR_URL=ws://localhost:8000
from dotenv import load_dotenvload_dotenv(override=True)import asynciofrom unpod import AsyncClientasync def main(): async with AsyncClient() as client: profiles = await client.voice_profiles.list(language="en") for p in profiles: print(p.id, p.name, p.gender, p.quality)asyncio.run(main())
Available profiles look like this. Copy the agent_profile_id you want and use
it as voice_profile in Step 4:
A Speech Pipe ties a voice profile to your agent. The agent_id is a string
you choose - it links the pipe to the AgentRunner you run in Step 7T.
from dotenv import load_dotenvload_dotenv(override=True)import asynciofrom unpod import AsyncClientasync def main(): async with AsyncClient() as client: pipe = await client.pipes.create( name="Support Bot", voice_profile="vp_riya", # profile_id from Step 3 (p.id) agent_id="my-support-agent", # your identifier - must match AgentRunner recording=True, max_call_duration_s=600, ) print("Pipe ID:", pipe.pipe_id)asyncio.run(main())
Save the pipe.pipe_id - you will use it in the steps below. A pipe without
agent_id will show as degraded and calls will not be dispatched to your
runner.
create_dialog_flow generates a structured conversation graph (nodes + edges)
from a plain-English description. Run it once and save the result.
from dotenv import load_dotenvload_dotenv(override=True)import asynciofrom superdialog import create_dialog_flowasync def main(): flow = await create_dialog_flow( prompt=( "You are Alex, a friendly support agent. " "Greet the user, ask how you can help, resolve their issue, " "and end the conversation when done." ), llm="anthropic/claude-haiku-4-5-20251001", # or "openai/gpt-4o-mini" ) flow.save("support.json")asyncio.run(main())
This writes support.json. Use it in your entrypoint with
DialogMachine(flow=Flow.load("support.json"), llm="...") for structured,
node-based conversations. For a simpler prompt-only agent, skip this step and
use AnthropicAdapter or LLMAgent directly in Step 7T.
agent_id is a string you define (e.g. "my-support-agent"). It must be
identical in both pipes.create() (Step 4) and AgentRunner below - this is
how Unpod routes inbound calls to your runner.
Create agent.py:
from dotenv import load_dotenvload_dotenv(override=True)import osfrom anthropic import AsyncAnthropicfrom unpod import AgentRunner, CallContextfrom unpod.adapters import AnthropicAdapterasync def handle_call(ctx: CallContext) -> None: ctx.session.dialog_machine = AnthropicAdapter( client=AsyncAnthropic(), model="claude-haiku-4-5-20251001", system_prompt=( "You are Alex, a friendly support agent. " "Greet the user, ask how you can help, resolve their issue, " "and end the conversation when done." ), ) await ctx.session.run()AgentRunner( entrypoint=handle_call, agent_id="my-support-agent", # must match agent_id in pipes.create() api_key=os.getenv("UNPOD_API_KEY"), max_sessions=10, agent_secret=os.getenv("UNPOD_AGENT_SECRET"), serving_url=os.getenv("UNPOD_RUNNER_URL"),).start()
Using the flow from Step 5 instead
If you ran Step 5, swap AnthropicAdapter for DialogMachine to drive a
structured node-based conversation:
Call the number you attached. The runner connects to the Unpod orchestrator and
dispatches inbound calls to your entrypoint. The process stays running and
accepts calls until you stop it.
No npm package needed for local dev. Open the Supervoice web dashboard:
http://localhost:3100
Point it at your pipe — it handles microphone capture, session token exchange,
and the audio bridge. The same AgentRunner from Step 7T handles both phone
and browser sessions with no changes.
@unpod/web-sdk is not yet published on npm. localhost:3100 is the local
Supervoice UI — start it before opening the browser demo.