Speech to Text

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

This page targets Azure CLI 2.90.0, the speech to text REST API 2025-10-15 and Speech SDK 1.52.0 (azure-cognitiveservices-speech, Microsoft.CognitiveServices.Speech, com.microsoft.cognitiveservices.speech:client-sdk), released in September 2026. The LLM speech SDKs (azure-ai-transcription, Azure.AI.Speech.Transcription, com.azure:azure-ai-speech-transcription) are at 1.0.0. Checked on 2026-10-06.

Azure Speech in Foundry Tools turns audio into text. It offers several modes that trade latency against file size and features. Choosing the right mode matters more than any other setting. The vendor-neutral background (streaming vs batch, accuracy factors, WER) is on Speech to Text. This page covers the Azure service.

The modes

Speech to text modes compared: real-time, fast transcription, batch and LLM speech by latency, file limits, diarization and translation
Mode How it works Choose it for

Real-time

Speech SDK streams audio over a WebSocket and returns partial and final results as the user speaks. Supports continuous recognition, phrase lists, language identification and multichannel audio.

Live captions, dictation, voice commands, voice search.

Fast transcription

Synchronous REST call, transcriptions:transcribe. Upload a file up to 500 MB and 5 hours and get the transcript in one response, usually much faster than real time. Diarization up to 35 speakers.

Short to medium recordings where you can wait seconds, not minutes: voicemail, meeting snippets, podcast episodes.

Batch transcription

Asynchronous REST. Point the job at Blob URLs or a whole container, poll for status, read results from Blob. Best-effort scheduling, no SLA on start time.

Large backlogs: call-center recordings, archives.

LLM speech (preview)

A large speech model with prompt tuning (for example MAI-Transcribe-2). Transcribe or translate in one pass. Uses the new Transcription SDKs.

Hard audio (accents, jargon) where prompts help, or transcribe-and-translate jobs.

Whisper / gpt-transcribe

Whisper is available through Speech batch transcription. gpt-transcribe and Whisper are also deployable as Foundry Models and called through the Azure OpenAI audio API.

Noisy or mixed-language audio when you don’t need diarization or word-level features.

Provisioning

In the Azure portal

  1. Create the Foundry resource foundry-bookshelf as shown on Resources, Endpoints and Authentication.

  2. Open the Foundry portal at https://ai.azure.com, select the project, then Playgrounds → Speech playground to try real-time and fast transcription on a recording.

  3. For custom speech, open Fine-tuning → AI Service fine-tuning → Custom speech. Speech Studio (https://speech.microsoft.com) still offers the same tools.

  4. Assign Cognitive Services Speech User (or Cognitive Services User) to the identity that calls the API.

With the Azure CLI

az cognitiveservices account show --name "$FOUNDRY" --resource-group "$RG" --query properties.endpoint -o tsv

az role assignment create \
  --assignee "$(az identity show --name id-catalog-api --resource-group "$RG" --query principalId -o tsv)" \
  --role "Cognitive Services Speech User" \
  --scope "$(az cognitiveservices account show --name "$FOUNDRY" --resource-group "$RG" --query id -o tsv)"

Real-time recognition with the Speech SDK

Continuous recognition from a WAV file, with a phrase list that boosts Bookshelf author names. The SDK uses the custom-subdomain endpoint and Entra ID.

import time
import azure.cognitiveservices.speech as speechsdk
from azure.identity import DefaultAzureCredential

speech_config = speechsdk.SpeechConfig(
    endpoint="https://foundry-bookshelf.cognitiveservices.azure.com/",
    token_credential=DefaultAzureCredential(),
)
speech_config.speech_recognition_language = "en-US"
audio_config = speechsdk.audio.AudioConfig(filename="voice-search.wav")
recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_config)

phrases = speechsdk.PhraseListGrammar.from_recognizer(recognizer)
for name in ["Ursula K. Le Guin", "Chimamanda Ngozi Adichie"]:
    phrases.addPhrase(name)

done = False
def stop(evt):
    global done
    done = True

recognizer.recognized.connect(lambda evt: print("FINAL:", evt.result.text))
recognizer.session_stopped.connect(stop)
recognizer.canceled.connect(stop)
recognizer.start_continuous_recognition()
while not done:
    time.sleep(0.5)
recognizer.stop_continuous_recognition()
using Azure.Identity;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;

var config = SpeechConfig.FromEndpoint(
    new Uri("https://foundry-bookshelf.cognitiveservices.azure.com/"), new DefaultAzureCredential());
config.SpeechRecognitionLanguage = "en-US";

using var audio = AudioConfig.FromWavFileInput("voice-search.wav");
using var recognizer = new SpeechRecognizer(config, audio);
PhraseListGrammar.FromRecognizer(recognizer).AddPhrase("Ursula K. Le Guin");

var stopped = new TaskCompletionSource<int>();
recognizer.Recognized += (_, e) => Console.WriteLine($"FINAL: {e.Result.Text}");
recognizer.SessionStopped += (_, _) => stopped.TrySetResult(0);
recognizer.Canceled += (_, _) => stopped.TrySetResult(0);

await recognizer.StartContinuousRecognitionAsync();
await stopped.Task;
await recognizer.StopContinuousRecognitionAsync();
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.microsoft.cognitiveservices.speech.*;
import com.microsoft.cognitiveservices.speech.audio.AudioConfig;
import java.net.URI;

SpeechConfig config = SpeechConfig.fromEndpoint(
    new URI("https://foundry-bookshelf.cognitiveservices.azure.com/"),
    new DefaultAzureCredentialBuilder().build());
config.setSpeechRecognitionLanguage("en-US");

try (AudioConfig audio = AudioConfig.fromWavFileInput("voice-search.wav");
     SpeechRecognizer recognizer = new SpeechRecognizer(config, audio)) {
    SpeechRecognitionResult result = recognizer.recognizeOnceAsync().get();
    if (result.getReason() == ResultReason.RecognizedSpeech) {
        System.out.println("FINAL: " + result.getText());
    }
}

For language identification, pass an AutoDetectSourceLanguageConfig with up to 4 candidate languages at start (or 10 in continuous mode). For multichannel audio (for example a stereo call recording with agent and customer on separate channels), batch and fast transcription handle each channel separately.

Fast transcription

Fast transcription is REST-only. Send the audio and a JSON definition as multipart form data:

TOKEN=$(az account get-access-token --resource https://cognitiveservices.azure.com --query accessToken -o tsv)

curl -s -X POST \
  "https://$FOUNDRY.cognitiveservices.azure.com/speechtotext/transcriptions:transcribe?api-version=2025-10-15" \
  -H "Authorization: Bearer $TOKEN" \
  -F "audio=@author-interview-042.mp3" \
  -F 'definition={"locales":["en-US"],"diarization":{"enabled":true,"maxSpeakers":2},"profanityFilterMode":"Masked"}'

The response has combinedPhrases (the full transcript per channel) and phrases (each phrase with speaker, offsetMilliseconds, durationMilliseconds, confidence and word timings).

Batch transcription

Batch transcription reads audio from Blob storage and writes results back. The Speech resource’s managed identity needs Storage Blob Data Reader on stbookshelf, or you pass SAS URLs.

sequenceDiagram participant Job as podcast-indexer job participant Blob as stbookshelf media container participant Speech as foundry-bookshelf Speech Job->>Blob: Upload episode MP3 files Job->>Speech: POST transcriptions:submit with contentContainerUrl Speech-->>Job: 201 Created, transcription self URL loop Every 30 to 60 seconds Job->>Speech: GET transcription status Speech-->>Job: NotStarted, Running or Succeeded end Speech->>Blob: Read audio with managed identity Job->>Speech: GET transcription files Speech-->>Job: contentUrl of each JSON result Job->>Job: Index transcript in search-bookshelf
TRANSCRIPTION_URL=$(curl -s -X POST \
  "https://$FOUNDRY.cognitiveservices.azure.com/speechtotext/transcriptions:submit?api-version=2025-10-15" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{
    "displayName": "author-interviews-2026-10",
    "locale": "en-US",
    "contentContainerUrl": "https://stbookshelf.blob.core.windows.net/media",
    "properties": {
      "diarization": {"enabled": true, "maxSpeakers": 3},
      "wordLevelTimestampsEnabled": true,
      "timeToLiveHours": 48
    }
  }' | jq -r .self)

# Poll the "self" URL returned above until "status" is "Succeeded" (or "Failed")
while :; do
  STATUS=$(curl -s "$TRANSCRIPTION_URL" -H "Authorization: Bearer $TOKEN" | jq -r .status)
  [ "$STATUS" = "Succeeded" ] || [ "$STATUS" = "Failed" ] && break
  sleep 30
done
curl -s "$TRANSCRIPTION_URL/files?api-version=2025-10-15" -H "Authorization: Bearer $TOKEN" \
  | jq -r '.values[] | select(.kind=="Transcription") | .links.contentUrl'

To use Whisper in batch, set "model": {"self": ".../models/base/<whisper-model-id>"} after listing base models with GET /speechtotext/models/base.

LLM speech (preview)

LLM speech uses the Transcription client libraries. A prompt can steer spelling and formatting:

from azure.ai.transcription import TranscriptionClient
from azure.ai.transcription.models import TranscriptionContent, TranscriptionOptions
from azure.identity import DefaultAzureCredential

client = TranscriptionClient(
    endpoint="https://foundry-bookshelf.cognitiveservices.azure.com/",
    credential=DefaultAzureCredential(),
)
with open("author-interview-042.mp3", "rb") as audio:
    result = client.transcribe(
        TranscriptionContent(
            definition=TranscriptionOptions(locales=["en-US"]),
            audio=audio,
        )
    )
print(result.combined_phrases[0].text)

Source: LLM speech

LLM speech is a preview feature with fewer languages and regions than the standard models. Check the release notes before you depend on it.

Diarization and conversation transcription

Diarization labels who spoke when (Guest-1, Guest-2 and so on). Batch and fast transcription do it on files. For live audio, ConversationTranscriber in the Speech SDK returns a speaker_id with each result. Speaker recognition (identifying a known person by voice) was retired on 2025-09-30. Diarization is not affected.

transcriber = speechsdk.transcription.ConversationTranscriber(
    speech_config=speech_config, audio_config=audio_config
)
transcribing_done = False
def stop_transcribing(evt):
    global transcribing_done
    transcribing_done = True

transcriber.transcribed.connect(lambda evt: print(evt.result.speaker_id, evt.result.text))
transcriber.session_stopped.connect(stop_transcribing)
transcriber.canceled.connect(stop_transcribing)
transcriber.start_transcribing_async().get()
while not transcribing_done:
    time.sleep(0.5)
transcriber.stop_transcribing_async().get()

Custom speech

Custom speech adapts the base model to your vocabulary and acoustics:

  • Plain text and structured text datasets teach domain words (titles, author names, product codes).

  • Pronunciation files map spoken forms to written forms.

  • Audio + human-labeled transcripts adapt to accents, noise or microphones.

You train a custom model, evaluate it against a held-out test set, and deploy an endpoint (billed per hour). The evaluation reports WER for the base and custom models side by side. The formula and how to read it are on Speech to Text — Word error rate.

REST API versions and retirements

  • 2025-10-15 is the current speech to text REST API (batch, fast transcription, custom speech, LLM speech).

  • 2024-11-15 is still supported.

  • The v3.0 and v3.2 preview versions were retired on 2026-03-31. Move v3.x calls to 2025-10-15. The main change is transcriptions:submit instead of POST /transcriptions.

Speech CLI

The Speech CLI (spx) is handy for quick tests and scripts:

dotnet tool install --global Microsoft.CognitiveServices.Speech.CLI
spx config @key --set "$SPEECH_KEY"
spx config @region --set eastus2
spx recognize --file voice-search.wav --language en-US --output file transcript.txt

This is the key-based quickstart path. Applications should use Entra ID as shown above.

Use cases

Scenario Feature Why this feature Example input → output

Bookshelf: transcribe author-interview podcasts for search

Batch transcription with diarization

Hundreds of hour-long episodes; no one waits for them; Blob in and out.

media/interview-042.mp3 → JSON with Guest-1/Guest-2 phrases, indexed in search-bookshelf

Bookshelf: voice search in the catalog

Real-time SDK with a phrase list

Sub-second partial results; author names boosted.

"books by Le Guin" spoken → books by Le Guin query to catalog-api

Call-center post-call analytics

Batch + diarization, then Language PII and an LLM summary

Agent and customer separated; PII removed before storage.

Stereo call → transcript per speaker → redacted summary

Live captions for events

Real-time continuous recognition

Captions must keep up with the speaker.

Keynote audio → caption stream on screen

Meeting minutes

Real-time ConversationTranscriber (or fast transcription) with diarization, then an LLM summary

Speakers separated, near-live; the summary turns the transcript into decisions and action items.

Meeting recording → per-speaker transcript → minutes with action items

Clinical dictation and notes

Real-time with custom speech, then Text Analytics for health

Medical vocabulary; structured output.

Doctor’s dictation → note → FHIR bundle

Subtitles for video

Fast transcription with word timestamps

One call per file; timings for SRT/VTT.

40-minute MP4 audio → WebVTT file

When not to use it

Clean up

curl -s -X DELETE "$TRANSCRIPTION_URL" -H "Authorization: Bearer $TOKEN"
az storage blob delete-batch --account-name stbookshelf --source media --pattern "interview-*" --auth-mode login