Overview
Pipecat ships two AssemblyAI speech-to-text services. This guide coversAssemblyAISyncSTTService, which transcribes one VAD-detected speech segment per HTTP request against the Sync API — no WebSocket to hold open, no session to manage.
Your local VAD decides where a turn ends; when it does, the segment is POSTed and the finished transcript comes back in the same call.
Available on
pipecat-ai 1.9.0+ — from pipecat.services.assemblyai.stt import AssemblyAISyncSTTService.Choosing sync or streaming
The Sync service is a different service class against a different API — not a mode of the streaming one.
Reach for the Sync service when your agent already relies on local VAD for turn-taking, when you want per-turn request/response semantics that are simple to retry, log, and reason about, or when you need per-word timestamps on each turn.
Reach for the streaming service when you want AssemblyAI to detect end-of-turn for you, when you need interim transcripts to drive UI or speculative inference, or when turns can run longer than 120 seconds.
Pipecat AssemblyAI STT plugin
View Pipecat’s AssemblyAI STT plugin reference.
Streaming on Pipecat
Build the same agent on Universal 3.5 Pro Realtime over a WebSocket.
Quickstart
1
Install Pipecat
Install Pipecat with the AssemblyAI, LLM, and TTS extras you need:What’s included:
assemblyai: AssemblyAI STT servicesopenai: OpenAI LLM service (used in the example)cartesia: Cartesia TTS service (used in the example)silero: Silero VAD — required, since the Sync service segments audio from VAD events
2
Set your API keys
Set your API keys in a
.env file:3
Build a minimal agent
Two things differ from a streaming agent: you create and own an
aiohttp.ClientSession and pass it to the service, and the assistant aggregator at the end of the pipeline is what feeds the agent’s replies into conversation context.4
Run and test
Run the agent directly with local audio:Speak into your microphone after hearing the greeting. Because there are no interim transcripts, the first thing you see per turn is the finished transcript, logged once the segment comes back.
How each turn is transcribed
AssemblyAISyncSTTService extends Pipecat’s SegmentedSTTService, so the segmentation is handled by the base class and the AssemblyAI service only transcribes what it’s handed. Per turn:
- VAD detects speech start. If pre-warming is enabled, the service fires a warm request in the background (see Connection pre-warming).
- Audio buffers into the current segment. A short lead-in is retained, so the delay between actual speech start and VAD detection doesn’t clip the first word.
- VAD detects speech end. The segment is closed, padded with a half-second of trailing silence so the model hears the end of speech and finishes the last word, and wrapped in a WAV container.
- The segment is POSTed as
multipart/form-data— the audio part plus aconfigpart built from your settings — and the transcript returns in the response. - A
TranscriptionFrameis pushed with the text, and the turn is appended to the conversation-context buffer for the next request.
This service emits no
InterimTranscriptionFrames — a turn produces exactly one final TranscriptionFrame, and empty transcripts are dropped rather than pushed. Anything in your pipeline that reacts to partials won’t fire.Parameters reference
Constructor arguments
str
required
Your AssemblyAI API key.
aiohttp.ClientSession
required
The HTTP session used for both warm and transcribe requests. Pre-warming only
helps when both share this session’s connection pool, so create one session and
keep it for the life of the service.
str
default:"https://sync.assemblyai.com"
Base URL for the Sync API. Override for a data-residency endpoint — see
Data residency.
int | None
default:"None"
Audio sample rate in Hz. Defaults to the pipeline’s rate.
bool
default:"True"
Open the connection when the user starts speaking so the transcription request
skips the handshake. See Connection pre-warming.
int
default:"5"
How many prior turns — user transcripts and agent replies together — are carried
as
conversation_context on each request. Set to 0 to disable automatic
context. Ignored when you set conversation_context yourself.int
default:"1500"
Character budget for the same buffer. Oldest turns are evicted first once either
cap is exceeded.
float
default:"0.65"
P99 latency from speech end to final transcript, in seconds, broadcast at
pipeline start for downstream turn timing. Set it to your own measured value.
Settings
Set these insideAssemblyAISyncSTTService.Settings(...).
str
default:"universal-3-5-pro"
The speech model, sent as the
X-AAI-Model header.Language
default:"Language.EN"
The transcription language. Superseded by
language_codes when both are set.list[Language]
default:"None"
Declared audio languages for multilingual or code-switching audio, e.g.
[Language.EN, Language.ES]. Regional variants resolve to their base code and
duplicates are dropped, preserving declaration order. See
Language selection.str
default:"None"
A natural-language description of what the audio is about — the domain, the
scenario, or details of the conversation. Maximum 6000 characters. See
Contextual prompting.
list[str]
default:"None"
Key terms or phrases to bias the decoder toward. See
Keyterms prompting.
str | list[str]
default:"None"
Prior turns, oldest first. Setting this turns off the service’s automatic
context buffer and sends exactly this value. Leave it unset to let the service
manage context. See Conversation context.
bool
default:"None"
Compute per-word
start/end times, returned on the words of the result, at a
small added latency. Unset means the API default (false) applies. See
Word timestamps.Conversation context
The Sync API is stateless: each request transcribes one clip with no memory of the last. Conversation context is how you give the model the surrounding dialogue anyway, and the Pipecat service assembles it for you. It keeps a rolling buffer of the most recent turns — user transcripts and agent replies together, in the order spoken — and sends them asconversation_context on every request. Agent replies are captured from the pipeline’s assistant-turn frame, so this needs no wiring beyond having the standard context aggregator pair in your pipeline:
Tuning the buffer
The buffer is bounded by both caps, and the oldest turns are evicted first when either is exceeded:
The defaults are deliberately conservative — every carried turn is uploaded again on the next request. Raise them when your conversations hinge on detail established several turns back:
max_context_turns=0 to turn automatic context off entirely.
Supplying context yourself
Settingconversation_context in Settings disables the automatic buffer and sends exactly your value — useful when your application already tracks the dialogue, or when you want to seed the model with context from before the call:
Connection pre-warming
Because each turn is its own HTTP request, connection setup would otherwise sit in the latency budget of every turn. Pre-warming takes it off the critical path: the service sends a warm request the moment VAD reports speech start, so DNS, TCP, and TLS complete while the user is still talking, and the transcribe request that follows starts uploading immediately. This is on by default. Two things are worth knowing:- The session must be shared. The warmed connection lives in your
aiohttp.ClientSessionpool. Passing a different session — or letting one be created per request — forfeits the saving entirely. - Warming is best-effort. Failures are logged at debug level and swallowed, since a failed warm-up only costs you the latency saving, never the transcription.
enable_prewarming=False to disable the automatic warm on speech start. See Connection pre-warming for what the handshake actually costs.
Data residency
Pointbase_url at a regional endpoint to keep audio and transcripts inside a zone:
https://sync.assemblyai.com) routes to the nearest available region, which may be in the US or the EU. See Cloud endpoints & data residency.
Error handling
A failed request is logged and pushed downstream as anErrorFrame rather than raised — the pipeline keeps running and that turn simply produces no transcript.
The HTTP status rides on the underlying exception so Pipecat can classify the failure: a rejected key (401) marks the service unusable, while a rate limit (429) or a server error (5xx) does not. That distinction is what processor_unusable_policy acts on:
ProcessorUnusablePolicy.END ends the run when a processor becomes unusable — better than an agent that keeps listening and never hears anything. See Error handling for the full status and error_code table.
Metrics
can_generate_metrics() returns True: each turn is a discrete request, so its duration is measured and reported through Pipecat’s usual metrics with enable_metrics=True.
For downstream turn timing, the service broadcasts ttfs_p99_latency at pipeline start — 0.65 seconds by default. Measure your own P99 from speech end to final transcript and set it explicitly; the default is a general figure and your network distance to the endpoint moves it.
Related
Streaming on Pipecat
The WebSocket service, with AssemblyAI’s built-in turn detection.
Sync STT quickstart
Use the Sync API directly, without Pipecat.
Prompting and keyterms
Improve accuracy with contextual prompts and key terms.
Audio requirements
Duration, size, format, and sample-rate constraints.