Swapping a TTS provider in a phone agent sounds like a one-line change. Change the import, change the API key, ship it.
Then the first call goes out and the agent reads [laughs] out loud, because the new provider doesn't speak ElevenLabs audio tags. Or your μ-law stream turns to static because the new API takes the encoding as two parameters instead of one ulaw_8000 string. Or you discover that "concurrency" means something different on the other side.
This guide is for teams that have already decided to evaluate alternatives to ElevenLabs for phone and voice agents. It covers five alternatives built for real-time voice (AssemblyAI, Inworld, Cartesia, Deepgram, and Rime), then spends most of its time on the part other lists skip: what changes in your config and code when you switch, and how to do it in LiveKit, Pipecat, and a raw Twilio loop.
The alternatives at a glance
Prices as of October 28, 2026, from each vendor's own pricing page. Concurrency and telephony details from each vendor's docs on the same date.
| Provider (model) | List price | How concurrency is limited | 8 kHz μ-law | Languages | LiveKit / Pipecat |
|---|---|---|---|---|---|
| ElevenLabs v4 Turbo (what you're leaving) | $0.04 per 1K characters | Text to Dialogue WebSocket: one session per open connection, 14 (Free) to 105 (Scale, Business); rejected past the limit | ulaw_8000 | 90+ | Plugin only (retired from LiveKit Inference Aug 31, 2026) / Service |
| AssemblyAI (AssemblyAI-TTS-1) | $15 per 1M characters | New sessions per minute; open sessions aren't counted | pcm_mulaw, pcm_alaw | 6 | Plugin and LiveKit Inference / AssemblyAITTSService in pipecat-ai 1.15.0+ |
| Inworld (TTS-2, TTS-2 Flash) | $25 / $15 per 1M characters (On-Demand) | Concurrent generations by plan: 5 (On-Demand) to 500 (Growth) | MULAW, ALAW | 200+ languages and locales | Plugin and LiveKit Inference / Service |
| Cartesia (Sonic 3.6) | Credit plans from $5/mo (100K) to $299/mo (8M); about 1 credit per character | Concurrent requests by plan: 2 (Free) to 15 (Scale); custom on Enterprise | pcm_mulaw | 44 | Plugin and LiveKit Inference / Service |
| Deepgram (Flux TTS, Aura-2) | Flux TTS $0.0450 per 1K characters | Up to 45 concurrent streaming requests on Pay as You Go (North America) | mulaw, alaw | Not compared here | Plugin and LiveKit Inference / Service |
| Rime (Mist v3, Coda v2) | $0.030 / $0.050 per minute (Flex) | Plan-based | audio/x-mulaw | Not compared here | Plugin and LiveKit Inference / Service |
Two columns deserve a second look. The concurrency column uses three different units (sessions, generations, and requests), so the numbers don't compare directly. And the pricing column mixes per-character and per-minute billing. Price a real month of your own call transcripts on each before you decide.
Why phone agents outgrow ElevenLabs
For phone agents, three things in ElevenLabs' own docs tend to start the conversation:
- Session-based limits on the newest models. ElevenLabs' models documentation says Text to Dialogue WebSocket connections are metered as dialogue sessions. An open connection holds a session for as long as it stays open, whether or not audio is being generated, and a connection opened past the plan's limit is rejected with too_many_concurrent_requests. If your agent holds one socket per call, that limit is your concurrent call ceiling.
- Idle connections close quickly. The same page says a dialogue connection closes after 20 seconds of inactivity unless you send keep-alive messages. Phone calls have long pauses while callers look things up.
- LiveKit Inference no longer serves it. LiveKit's ElevenLabs plugin page says ElevenLabs was retired from LiveKit Inference on August 31, 2026. The plugin still works with your own ElevenLabs account.
None of that is a reason to switch on its own. If your agent needs 90+ languages or pronunciation dictionaries, those are real constraints on where you can go.
The alternatives, one by one
Each entry answers the same question: if you leave ElevenLabs for this provider, what do you gain and what do you give up?
AssemblyAI
AssemblyAI-TTS-1 is a text-to-speech model built for conversational voice agents, trained on millions of hours of audio, including real conversational data. It's frontier-level quality, faster than other production voice agent TTS models, and comes with thousands of voices and instant voice cloning in the dashboard.
What you gain: a concurrency model that counts call starts rather than open calls (more on that below), native pcm_mulaw and pcm_alaw at 8 kHz, US and EU data zones, $15 per 1M characters with no commitment, and the option to run speech-to-text, the LLM, and TTS on one API key with Universal-3.6 Pro Realtime and LLM Gateway.
What you give up: languages (six: English, Spanish, French, German, Italian, and Portuguese, with no automatic detection). Fine control too: the connection parameter docs say there's no speed, pitch, emotion, style, or stability parameter, and no pronunciation dictionary or SSML. Delivery is steered through the text itself, as the prompting guide describes.
How it benchmarks against ElevenLabs: in our evals from the launch post, AssemblyAI-TTS-1 scored 93.7% entity accuracy (phone numbers, dates, URLs, confirmation codes, drug names), level with ElevenLabs v4 at 93.6% and well ahead of ElevenLabs Flash v2.5 at 68.0%. On the independent Cekura leaderboard, it read phone numbers and codes correctly 92% of the time vs 89% for the best ElevenLabs model, and scored 4.50 on naturalness vs 4.42.
Inworld
TTS-2 and TTS-2 Flash cover 200+ languages and locales. Pricing is per character and drops on monthly plans.
What changes for a phone agent: concurrency is counted in generations. Inworld's concurrency docs list 5 concurrent generations on On-Demand and 500 on Growth, with WebSocket connections capped separately at 10 times the generation limit. Requests above the generation limit are best-effort.
Cartesia
Sonic 3.6 is generally available with 44 languages and outputs pcm_mulaw for telephony.
What changes for a phone agent: billing moves from characters to plan credits (about one credit per character), so a month's cost depends on which plan bucket you land in. Its pricing page caps TTS at 2 concurrent requests on Free, 3 on Pro, 5 on Startup, and 15 on Scale, with custom limits on Enterprise.
Deepgram
Flux TTS and Aura-2 stream over WebSocket and output mulaw or alaw at 8 kHz.
What changes for a phone agent: concurrency is a fixed number of simultaneous requests. Deepgram's rate-limit docs list up to 45 concurrent streaming TTS requests on Pay as You Go in North America, counted per project, and say extra projects on the same account don't add concurrency.
Rime
Mist v3 and Coda v2 are billed per minute of audio rather than per character, and Rime also licenses standalone engines for on-prem deployment.
What changes for a phone agent: its WebSocket v1 cancels a reply by context for barge-in. The legacy /ws binary endpoint can only interrupt by closing the connection, so pick v1 for a new build.
Paste a few lines your agent actually says and compare voices before you change any code.
Is there a free ElevenLabs alternative?
Every provider here has a way to start without a contract. They aren't equivalent, so check what each one includes:
- Rime lists a free plan with $50 of usage every month, no card required.
- Inworld lists an On-Demand plan at $0 per month, pay as you go, with up to 70 minutes of TTS included.
- Cartesia lists a free plan with 20K credits.
- ElevenLabs has a free plan, and its dialogue session limit is lowest there (14 sessions).
- AssemblyAI has a free plan; its TTS limits list 5 new sessions per minute on it, and you can sign up without a sales call. Check the pricing page for current free usage.
If "free" means open source and self-hosted, none of these five fit. That's a different trade: you run the GPUs and own the latency.
What changes when you switch
This is the checklist. Most migration bugs come from one of these rows.
| What you configured in ElevenLabs | What it becomes on AssemblyAI TTS | Watch out for |
|---|---|---|
| voice_id from the ElevenLabs voice library | voice_id (a UUID) from the AssemblyAI voice catalog, via Copy voice ID | Voice IDs don't carry over. Pick a voice recorded in your agent's language |
| Cloned voice | Re-create it in the AssemblyAI dashboard from a short reference recording | The speaker must accept biometric consent terms; consent lasts 60 days unless renewed |
| model_id (eleven_v4_turbo, eleven_flash_v2_5) | model assemblyai-tts-1 | One model speaks all six languages |
| output_format ulaw_8000 | encoding pcm_mulaw plus sample_rate 8000 | Two parameters instead of one string. A-law is pcm_alaw |
| language_code | language, as a full English name ("spanish") on the API or a code ("es") in the LiveKit plugin | No detection: set it to the language your LLM writes |
| voice_settings (stability, similarity_boost, style, speed) | No equivalent | Steer delivery with punctuation, capitalization, and filler words in the text |
| Audio tags such as [laughs] | Read aloud as words | Strip tags from LLM output before sending |
| Pronunciation dictionaries | No equivalent | Write uncommon terms out; dash-separate acronyms (E-T-O) and digits (4-3-2-1) |
| Alignment data for interrupted replies | Word boundaries (per-word timings) | On by default on the raw WebSocket, off by default in the SDKs |
| xi-api-key header | Authorization header with your AssemblyAI key | Use temporary tokens for browser clients |
| Concurrency: requests or dialogue sessions per plan | New sessions per minute, matching your streaming speech-to-text limit | Reuse one session per call; don't open one per utterance |
| Idle close (20 s on dialogue sockets) | Idle close after 2 minutes, adjustable with inactivity_timeout | Send keep_alive during long caller pauses |
| Data residency on Enterprise workspaces | EU data zone at tts.eu.assemblyai.com | Cloned voices work only in the zone where you created them |
The concurrency row is the one to model before you migrate. The TTS limits docs count new sessions per minute and never count sessions already open. A voice agent keeps one session for the whole call, so your limit is how many calls can start in a minute. With a limit of 100, for example, 100 calls can start in one minute and 110 in the next, and all 210 stay connected. That's how unlimited concurrency works in practice: capacity grows with your call volume and never requires negotiation.
Universal-3.6 Pro Realtime, LLM Gateway, and AssemblyAI TTS, with native 8 kHz μ-law and no commitment.
Switching inside LiveKit, Pipecat, and a Twilio loop
LiveKit
In LiveKit Agents, the swap is the tts= argument and an environment variable. Here's the ElevenLabs plugin as LiveKit's docs show it:
from livekit.agents import AgentSession
from livekit.plugins import elevenlabs
session = AgentSession(
tts=elevenlabs.TTS(voice_id="ODq5zmih8GrVes37Dizd", model="eleven_multilingual_v2"),
# ... llm, stt, etc.
)And the AssemblyAI plugin, from the AssemblyAI LiveKit TTS docs:
from livekit.agents import AgentSession
from livekit.plugins import assemblyai
tts = assemblyai.TTS(
model="assemblyai-tts-1",
voice="49c443a4-8a1d-5f7e-b70b-98bdbd9823c3", # Audrey
)
tts.prewarm() # open the session before the first reply
session = AgentSession(
tts=tts,
# When the user interrupts, keep only the words they heard in the chat history
use_tts_aligned_transcript=True,
# ... llm, stt, etc.
)Install livekit-plugins-assemblyai>=1.8.9, replace ELEVEN_API_KEY with ASSEMBLYAI_API_KEY in your .env, and add filter_markdown and filter_emoji to tts_text_transforms if your LLM produces them. If you'd rather keep billing in LiveKit Cloud, LiveKit's AssemblyAI TTS page shows the Inference route, assemblyai/assemblyai-tts-1, for library voices.
Pipecat
In Pipecat, the swap is one service in the pipeline. The ElevenLabs service, from Pipecat's docs:
import os
from pipecat.services.elevenlabs.tts import ElevenLabsTTSService
tts = ElevenLabsTTSService(
api_key=os.getenv("ELEVENLABS_API_KEY"),
settings=ElevenLabsTTSService.Settings(
voice="21m00Tcm4TlvDq8ikWAM",
model="eleven_flash_v2_5",
),
)And the AssemblyAI service:
import os
from pipecat.services.assemblyai.tts import AssemblyAITTSService
tts = AssemblyAITTSService(
api_key=os.environ["ASSEMBLYAI_API_KEY"],
settings=AssemblyAITTSService.Settings(
model="assemblyai-tts-1",
voice="49c443a4-8a1d-5f7e-b70b-98bdbd9823c3", # Audrey
),
)AssemblyAI's AssemblyAITTSService shipped in pipecat-ai 1.15.0 (October 28, 2026). Install it with the assemblyai extra; the AssemblyAI Pipecat TTS docs have the full setup.
A raw Twilio loop
If you talk to Twilio Media Streams directly, the change is in the session config. With ElevenLabs you asked for ulaw_8000. With the AssemblyAI Python SDK, you set the encoding and rate separately, then forward each chunk as a base64 media message:
import base64
import json
import os
import assemblyai as aai
config = aai.TTSConfig(
voice_id="49c443a4-8a1d-5f7e-b70b-98bdbd9823c3", # Audrey
language="english",
encoding=aai.TTSEncoding.pcm_mulaw, # was output_format="ulaw_8000"
sample_rate=8000,
)
async def speak(twilio_ws, stream_sid, session, text):
async for chunk in session.speak(text):
await twilio_ws.send_text(json.dumps({
"event": "media",
"streamSid": stream_sid,
"media": {"payload": base64.b64encode(chunk).decode()},
}))
# One session per call, kept open for every turn:
# async with aai.AsyncTTSSession(config, api_key=os.environ["ASSEMBLYAI_API_KEY"]) as session:
# await speak(twilio_ws, stream_sid, session, "Thanks for calling. How can I help?")For barge-in, call session.cancel() and send Twilio a clear event. For streamed LLM output, use generate() per token and flush() at the end of the reply, as the quickstart shows. Our Twilio voice agent tutorial has the full server, including speech-to-text.
Test before you cut over
Run both providers side by side on a slice of real traffic before you flip the default. Score the things a caller notices: whether order numbers, prices, and names come through correctly at 8 kHz, how fast the first word arrives, and whether interruptions stop the agent cleanly. Our guide on how to evaluate TTS for voice agents has a scoring method, and AssemblyAI vs ElevenLabs for voice agents covers the platform-versus-speech-layer question if you're also reconsidering ElevenLabs for speech-to-text.
The real lesson from most migrations is that the voice was never the hard part. The hard part was every assumption the old provider baked into your code: tag syntax, encoding strings, idle timeouts, and what a "concurrent" request meant. Write those down as the checklist above, and the next switch is an afternoon instead of a sprint.
Get an API key, set encoding to pcm_mulaw, and run your first call on AssemblyAI TTS.
Frequently Asked Questions (FAQs)
What is the best ElevenLabs alternative for AI phone agents?
It depends on what's pushing you off ElevenLabs. If concurrency and cost at volume are the problem and your calls are in English, Spanish, French, German, Italian, or Portuguese, AssemblyAI TTS counts call starts instead of open calls and costs $15 per 1M characters. If you need 90+ languages, look at Inworld's 200+ languages and locales.
Is there a free alternative to ElevenLabs for voice agents?
Yes, several providers let you start free. Rime lists $50 of usage a month with no card, Inworld's On-Demand plan includes up to 70 minutes of TTS, and Cartesia's free plan includes 20K credits. AssemblyAI has a free plan with 5 new TTS sessions per minute; check its pricing page for included usage.
What replaces ulaw_8000 when I switch from ElevenLabs to AssemblyAI?
Set two parameters instead of one string: encoding to pcm_mulaw and sample_rate to 8000. That produces raw 8 kHz μ-law with no header, which is what Twilio Media Streams expect. For A-law networks, use pcm_alaw. The model's native rate is 24 kHz, so 8 kHz output is resampled on the server.
Can I move my ElevenLabs cloned voice to another provider?
No, voice IDs and clones don't transfer between providers. Re-create the clone from a short reference recording in the new provider's dashboard. On AssemblyAI, the speaker must accept biometric consent terms, the clone works in the data zone where it was created, and consent lasts 60 days unless renewed.
Does AssemblyAI TTS support ElevenLabs audio tags or SSML?
No. AssemblyAI TTS has no SSML, audio tags, pronunciation dictionaries, or stability and speed settings. Bracketed tags like [laughs] are read aloud as words, so strip them before sending text. Steer delivery with punctuation, capitalization for stress, and filler words written into the text.
How does ElevenLabs API pricing compare to alternatives?
As of October 28, 2026, ElevenLabs lists v4 Turbo at $0.04 per 1K characters and v4 at $0.08 per 1K. AssemblyAI TTS is $15 per 1M characters, Inworld TTS-2 Flash is $15 per 1M On-Demand, and Rime bills per minute of audio. Price a month of your own transcripts, since units differ.