DEV Community

Mart Schweiger
Mart Schweiger

Posted on • Originally published at assemblyai.com

Sync HTTP for Voice Agents: Skip the WebSocket (2026)

Most voice agent tutorials — including our own guide to building a chained STT-LLM-TTS architecture — assume WebSockets. You open a streaming connection to your speech-to-text provider, manage it for the life of the call, and handle a live event model. For a lot of agents, that's the right design.

But it's not the only one. Some of the most sophisticated voice-agent teams deliberately don't stream their transcription. They send audio to STT as plain HTTP requests — one request per turn — and they do it on purpose. This post is about that pattern: when a sync HTTP call beats a WebSocket, and how to build an agent around it.

Why anyone would skip streaming

Streaming feels like the obvious choice for live conversation, so the instinct is to treat "not streaming" as cutting a corner. It isn't. It's a different set of tradeoffs, and for the right team the HTTP path is the simpler, more scalable one.

Several large voice-agent teams asked us for exactly this — a sync HTTP API for real-time transcripts — for a specific reason: they already run their LLM and text-to-speech as HTTP services, and they want their whole stack to look the same. Stateless request/response services are easier to scale, easier to load-balance, and easier to reason about than long-lived stateful connections. They're willing to accept slightly higher per-turn latency to get an architecture where every component is a plain HTTP call.

The other reason is turn detection. If you already run your own voice-activity detection — deciding when the user has started and stopped talking — a streaming model's built-in end-of-turn logic is redundant. You don't want the STT layer guessing when the turn ends; you already know, because your VAD just told you. At that point a persistent socket is overhead. You have a discrete chunk of audio and you want text back. That's a request, not a stream.

How the sync HTTP pattern works

The shape is simple, and if you've built a cascaded agent it'll look familiar — just with the STT stage swapped from a socket to a call:

  1. Your VAD detects the user has started speaking and buffers the audio.
  2. Your VAD detects end-of-turn and closes the buffer — a clip, usually a few seconds.
  3. You POST that clip to the Sync API and get the transcript back in the same response (~134ms p50, clips up to 2 minutes).
  4. You hand the text to your LLM (an HTTP call), then the LLM's reply to your TTS (another HTTP call).
  5. Repeat for the next turn.

Every stage is a stateless HTTP request. There's no connection to keep alive between turns, no streaming state to manage, no reconnection logic. The whole agent is a loop of request/response calls, which is exactly the property those teams were after. See the Sync API docs for the full request and response format.

# One turn, once your VAD has handed you a completed clip.
# Send audio as multipart/form-data with an "audio" part; model set via header.

import requests

session = requests.Session()  # reuse the connection across turns
SYNC_ENDPOINT = "https://sync.assemblyai.com/transcribe"
API_KEY = "YOUR_ASSEMBLYAI_API_KEY"

def transcribe_turn(wav_bytes: bytes) -> str:
    r = session.post(
        SYNC_ENDPOINT,
        headers={"Authorization": API_KEY, "X-AAI-Model": "u3-sync-pro"},
        files={"audio": ("clip.wav", wav_bytes, "audio/wav")},
        timeout=10,
    )
    r.raise_for_status()
    return r.json()["text"]

def handle_turn(wav_bytes):
    transcript = transcribe_turn(wav_bytes)   # STT  HTTP
    reply = run_llm(transcript)               # LLM  HTTP
    audio = synthesize(reply)                 # TTS  HTTP
    play(audio)
Enter fullscreen mode Exit fullscreen mode

Reusing a single requests.Session across turns keeps the TCP/TLS connection warm, so you're not paying handshake cost on every utterance — a small detail that matters when you're chaining three HTTP calls per turn.

The tradeoffs, honestly

This pattern isn't free. Here's what you're trading.

You give up mid-utterance transcription. A streaming model can start feeding partial text to your LLM before the user finishes talking. The sync pattern waits for the complete clip, so the LLM starts a beat later. For many agents that's imperceptible; for latency-obsessed ones it's the reason to stream.

You own turn detection — which is the point, but also the work. The whole pattern assumes your VAD is good. If it isn't, you'll clip users off or leave dead air, and no fast transcription will save you. If you'd rather not own that logic, a streaming model with built-in end-of-turn detection is the better fit — and if you specifically want to keep owning it while getting fast ASR back, that's its own design worth reading up on separately.

You accept slightly higher per-turn latency for architectural simplicity. That's the deal the teams who asked for this made knowingly. If your product can absorb it, you get a stack that's dramatically easier to scale and debug.

What you keep is accuracy. The Sync API returns the same transcript quality as async, so choosing the HTTP path costs you nothing on the words themselves — which, in an agent, is the thing you least want to compromise. Get the input wrong and the LLM answers the wrong question.

When to use it — and when to reach for the Voice Agent API instead

Use the sync HTTP pattern when you already run your own orchestration and VAD, you want a uniform stateless stack, and your latency budget has room for per-turn request/response. It's a builder's pattern for teams who want maximum control over how the pieces fit together.

If you don't want to wire STT, LLM, TTS, turn detection, and interruption handling together yourself, that's a different job — and it's what the Voice Agent API is for. One WebSocket connection handles the full pipeline at a flat $4.50/hr, built on Universal-3.5 Pro Realtime, with turn detection and barge-in included. The sync HTTP pattern is for teams who want to own the orchestration; the Voice Agent API is for teams who want it handled. Both are valid — the right call depends on how much of the stack you want in your hands.

Frequently asked questions

What is the sync HTTP pattern for voice agents?

The sync HTTP pattern is a voice-agent design where each conversational turn is transcribed with a single stateless HTTP request instead of a persistent WebSocket stream. Your own voice-activity detection decides when a turn ends, you POST that completed audio clip to a synchronous speech-to-text endpoint, and the transcript comes back in the same response. Every stage of the agent — STT, LLM, TTS — becomes a plain request/response call, so there's no streaming connection to keep alive between turns.

When should a voice agent use a sync HTTP API instead of a streaming WebSocket?

Use the sync HTTP pattern when you already run your own turn detection and want your whole stack to be uniform, stateless HTTP services that are easy to scale, load-balance, and debug. It's the better fit when your latency budget can absorb waiting for a complete clip per turn in exchange for architectural simplicity. Choose streaming instead when you need mid-utterance partial transcripts or you'd rather the STT model handle end-of-turn detection for you.

Does the sync HTTP pattern add latency compared to streaming?

It adds a small amount. A streaming model can feed partial text to your LLM before the user stops talking, while the sync pattern waits for the complete clip and then returns a transcript in roughly 134 ms at p50. For many agents that difference is imperceptible; for latency-obsessed applications, streaming's mid-utterance head start is the reason to stream. The tradeoff buys you a dramatically simpler, stateless architecture.

Do I need my own voice-activity detection (VAD) to use the sync pattern?

Yes — the pattern assumes you own turn detection. Your VAD decides when the user has started and stopped talking, then hands a completed clip to the Sync API for transcription. That's the point of the pattern for teams who already run their own VAD, but it's also the work: if your turn detection is weak, you'll clip users off or leave dead air, and fast transcription won't fix that. If you'd rather not own that logic, a streaming model or the Voice Agent API with built-in turn detection is the better choice.

Should I use the sync HTTP pattern or AssemblyAI's Voice Agent API?

Use the sync HTTP pattern if you want to own the orchestration — wiring STT, LLM, TTS, turn detection, and interruption handling together yourself for maximum control. Use the Voice Agent API if you want that pipeline handled for you: one WebSocket connection at a flat $4.50/hr, built on Universal-3.5 Pro Realtime, with turn detection, barge-in, and tool calling included. Both are valid — the right call depends on how much of the stack you want in your hands.

How do I get started with the Sync API, and what are its limits?

Create a free AssemblyAI account, then POST a completed audio clip with your API key and read the transcript straight off the response — no WebSocket, no polling. The Sync API accepts clips from 80 ms up to 2 minutes (40 MB max) across 18 languages, runs on Universal-3.5 Pro, and is priced at $0.45/hr of audio with keyterms prompting and conversation context included. See the Sync API docs for the full request and response format.

Top comments (0)