unmute deploy --target twilio performs only the last step.
1. Set up Twilio
- Create a Twilio account, then buy a voice-capable number. Follow the account and country requirements linked there.
- In Twilio Console, copy the Account SID and Auth Token. Open your
active number and copy its Phone Number SID (
PN…). - Accept the Predictive and Generative AI/ML Features Addendum in Voice settings, following ConversationRelay onboarding. This integration uses the number’s webhook, so skip the TwiML App setup.
- Use a number without a TwiML App, SIP trunk, or voice fallback URL. These conflict with the webhook; Unmute refuses to overwrite them.
us1, the default), Ireland
(ie1), and Australia (au1). This is where Twilio processes calls, separate
from your app host and SLNG’s world_part. For Ireland, use the
regional setup steps before connecting
the number. See Twilio’s regional support.
2. Create an agent
instructions.md: replace the starter’s browser identity with your
telephone assistant’s role. Keep replies short and suitable for speech. Add
this instruction: “When the caller is finished, call end_call in the same
turn as your goodbye.” The starter includes that tool; saying goodbye alone
does not hang up.
The default LLM binding is SLNG Context Router, with OpenAI upstream.
SLNG reuses answers it judges cacheable and calls the upstream model for other
requests. Twilio handles speech; SLNG optimizes the LLM side. The app forwards
your upstream key to SLNG on every model request. Keep agent_id stable for
cache reuse, and change it when prompt edits should invalidate old answers.
See Context Router.
3. Compile and configure
.env with these values. Leave TWILIO_PUBLIC_URL blank
until your host assigns a URL in step 4. Keep .env out of version control.
This runs on your computer.
unmute compile writes the deployable project
in build/twilio/: app.py, a Dockerfile, dependencies, tools, and a runbook.
It creates the FastAPI HTTP and WebSocket endpoints for you; you do not write
another server. Compile again after changing the source agent.
4. Host the application
Twilio requires a reachable secure WebSocket server. FastAPI is Unmute’s implementation choice; Twilio does not run your Python app. Twilio’s requirements apply whichever host you choose.Deploy the generated project
Choose one path. Runningdocker build or docker run on your laptop alone
does not publish the app to the internet.
- Container host (Render example)
- VM or Python host
-
Create an empty Git repository for the generated app. From
my-agent/, copy the build to a separate deployment folder, excluding local secrets:Replace the repository URL with yours. Keep editing the originalmy-agent/package; compile replaces its build folder. -
In Render, choose New → Web Service, connect that repository and its
mainbranch, and select Docker. Leave Root Directory empty, use./Dockerfilewith build context., and leave Docker Command empty. The Dockerfile installs dependencies and startspython app.py. Render Docker setup. -
Choose one always-on instance. Set Health Check Path to
/healthzandPORT=8080. In Environment, add the four keys from step 3:SLNG_API_KEY,OPENAI_API_KEY,TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN. -
Create the service and copy its assigned HTTPS URL. Set
TWILIO_PUBLIC_URLin Render’s Environment to that exact origin, for examplehttps://my-agent.onrender.com, with no path or trailing slash. Save and deploy the updated environment. The app requires this value to start; if the first attempt ran without it, redeploy after setting it. Render web services. -
Allow at least 35 seconds for shutdown. With the
Render CLI, use your service’s
srv-…ID:Render supplies HTTPS and forwards WebSocket connections to the same app port. No separate WebSocket service is needed. Wait until the deployment is Live, then return tomy-agent/on your computer.
Try it on a laptop with a tunnel
Try it on a laptop with a tunnel
From Copy the tunnel’s HTTPS origin into Keep both terminals running. Continue to step 5 using that tunnel URL.
When it changes, update
my-agent/, build locally:TWILIO_PUBLIC_URL in your local .env.
In a second terminal, from my-agent/, start the app:.env, restart the app, and reconnect the number.Set the public URL and check the hosted app
For every deployment, put the host’s exact HTTPS origin in the originalmy-agent/.env on your computer as well as the running app’s environment:
YOUR-HOST with the real hostname, such as my-agent.onrender.com.
Check it from your computer:
artifact_id.
A local health check does not establish that Twilio can reach the app.
Keep the service available when calls arrive; sleeping services can miss calls.
5. Connect the number
Now the app is hosted. From the originalmy-agent/ directory on your computer,
set TWILIO_PHONE_NUMBER_SID in .env to the number’s PN… SID and run:
/voice response, saves
the previous route, and sets the number’s incoming-call webhook. It uploads
no application. Routing and rollback details.
You can verify the webhook under Phone Numbers → Manage → Active numbers →
your number → Configure in Twilio Console. The WebSocket URL belongs in the
app’s generated TwiML, not the number’s webhook field. Both endpoints already
exist in
app.py and use the same host and port.
After edits: compile locally, publish the updated build to your host, wait for
it to become healthy, then run unmute deploy again to verify the matching build.
How a call reaches your agent
The app manages history, tools, and model requests. It validates Twilio signatures and streams responses with completion markers. A marker means text was sent, not that playback finished. Failed model turns get a short fallback response; three consecutive failures end the call.6. Make the first call
Call your number. Check the greeting, ask a question, interrupt a reply, and ask the agent to end the call. Confirm that it disconnects.end_call can
cut off a goodbye spoken in the same turn; do not rely on final speech being
fully played.
If something fails, read the app’s logs and the call in Twilio Console’s call
inspector. A signature error usually means TWILIO_PUBLIC_URL or the Auth
Token differs between Twilio, the host, and your local configuration. A build
ID mismatch means you need to host the newly compiled app. A silent or failed
model turn calls for checking both model keys and the model error in the log.
For Twilio’s own guidance, see best practices,
the Python/FastAPI tutorial,
and its example code.