Skip to main content

Overview

Pipecat ships two AssemblyAI speech-to-text services. This guide covers AssemblyAISyncSTTService, 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 services
  • openai: 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
The example uses OpenAI and Cartesia, but you can use any LLM or TTS supported by Pipecat — just swap the extras.
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.
The complete runnable example lives in the Pipecat repo: voice-assemblyai-sync.py.
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:
  1. VAD detects speech start. If pre-warming is enabled, the service fires a warm request in the background (see Connection pre-warming).
  2. 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.
  3. 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.
  4. The segment is POSTed as multipart/form-data — the audio part plus a config part built from your settings — and the transcript returns in the response.
  5. A TranscriptionFrame is pushed with the text, and the turn is appended to the conversation-context buffer for the next request.
Transcription runs off the audio path: segments are queued and transcribed in order by a background task while audio keeps flowing through the service. A graceful stop transcribes what’s queued; a cancel drops it.
Turns are capped at 120 seconds. The Sync API rejects longer audio with a 413. If your callers can monologue past two minutes, use the streaming service instead. See Audio requirements for the full constraints.
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 inside AssemblyAISyncSTTService.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.
language and language_codes are ignored when prompt is set. If you use a custom prompt and need a non-English language, state the language as part of the prompt text — see Specifying the language.

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 as conversation_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:
A turn never appears in its own request’s context: the config is built before the response is recorded.

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:
Set max_context_turns=0 to turn automatic context off entirely.

Supplying context yourself

Setting conversation_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:
This is a static value — the service won’t append to it. To change it mid-conversation, push an update; because every request rebuilds its config from the current settings, the new value applies to the next turn with no reconnect:

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.ClientSession pool. 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.
To warm at some other moment — say, when a call connects, before anyone speaks:
Set enable_prewarming=False to disable the automatic warm on speech start. See Connection pre-warming for what the handshake actually costs.

Data residency

Point base_url at a regional endpoint to keep audio and transcripts inside a zone:
The default (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 an ErrorFrame 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.

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.