For AI agents: a documentation index is available at /llms.txt. Markdown versions of all pages can be requested by appending `.md` to the URL, or by setting the `Accept` header to `text/markdown`.
Skip to main content
Speech to TextAgent STT

Quickstart

Transcribe a conversation with Agent STT.

Agent STT returns transcription a segment at a time and reports the speech and turn events a voice agent needs, so you know when a speaker has finished and the transcript is ready to send to an LLM.

Using the Agent STT SDK

The Agent STT SDK is a Python client for the Agent STT service. It runs no VAD or turn detection of its own — either the service closes turns, or your application does.

To view the source, see speechmatics-agent-stt on GitHub.

1. Create an API key

Create an API key in the portal, which you'll use to securely access the API. Store the key as a managed secret. See Authentication for temporary keys and other options.

Enterprise customers may need to speak to Support to get your API keys.

2. Install the SDK

pip install speechmatics-agent-stt pyaudio

pyaudio is required for microphone input in this quickstart.

3. Run the example

Set your API key in the environment, then run the script:

export SPEECHMATICS_API_KEY=<your-api-key>
import asyncio

from speechmatics.agent_stt import AgentSttAsyncClient
from speechmatics.agent_stt import Microphone
from speechmatics.agent_stt import Model
from speechmatics.agent_stt import ServerMessageType
from speechmatics.agent_stt import TranscriptionConfig

SAMPLE_RATE = 16000
CHUNK_SIZE = 1024


async def main() -> None:
mic = Microphone(sample_rate=SAMPLE_RATE, chunk_size=CHUNK_SIZE)
if not mic.start():
print("PyAudio not installed - install with: pip install pyaudio")
return

# Uses SPEECHMATICS_API_KEY from the environment
client = AgentSttAsyncClient(
transcription_config=TranscriptionConfig(
model=Model.LINDEN_1,
language="en",
enable_partials=True,
diarization="speaker",
)
)

# Register handlers before the session opens, so no message arrives unhandled
@client.on(ServerMessageType.ADD_PARTIAL_SEGMENT)
def handle_partial_segment(message):
print(f"[partial] {message['segment']['transcript']}")

@client.on(ServerMessageType.ADD_SEGMENT)
def handle_segment(message):
speaker = message["segment"].get("speaker", "?")
print(f"[final] {speaker}: {message['segment']['transcript']}")

@client.on(ServerMessageType.END_OF_TURN)
def handle_end_of_turn(message):
print(f"[turn] end at {message['metadata']['end_time']}s")

async with client:
print("\nMicrophone ready - speak now (Ctrl+C to stop)\n")
try:
while True:
await client.send_audio(await mic.read(CHUNK_SIZE))
except (asyncio.CancelledError, KeyboardInterrupt):
pass
finally:
mic.stop()

print(f"\nTranscript: {client.transcript_text(speaker_labels=True)}")


try:
asyncio.run(main())
except KeyboardInterrupt:
pass

Speak into your microphone. You should see partials as you talk, then a final segment when the turn closes:

[partial] hello I'd like to check on my
[final] S1: Hello, I'd like to check on my order.
[turn] end at 3.24s

Press Ctrl+C to stop.

Understanding the output

Read the text from message["segment"]["transcript"], and the speaker label from message["segment"]["speaker"].

  • AddPartialSegment — an interim preview. Each one replaces the previous, so don't concatenate them.
  • AddSegment — the finalized segment, and the stable output to pass to your LLM. Expect several per turn.
  • EndOfTurn — the speaker has finished and your agent can respond.

See Segmentation for what closes a segment and how speaker labels work.

Choosing who closes the turn

By default the service closes turns itself, from voice activity. If something upstream already detects that a speaker has finished — Pipecat, LiveKit, a push-to-talk button — start the session in external mode and close each turn yourself:

from speechmatics.agent_stt import TurnConfig, TurnDetectionMode

client = AgentSttAsyncClient(
transcription_config=TranscriptionConfig(language="en"),
turn_config=TurnConfig(turn_detection_mode=TurnDetectionMode.EXTERNAL),
)

Then close each turn when your side decides speech has ended:

client.finalize()

The call is stamped with the audio position at the moment it was made, so the service cuts the turn where you heard speech stop rather than wherever the message lands. In this mode nothing else closes a turn — an application that stops calling finalize() never sees another EndOfTurn. See Turn detection.

Next steps