Speech TranslationSpeech-to-text translation

Async speech-to-text translation

Translate recorded audio files in a single API call, with no live connection required.

Overview

Soniox async speech-to-text translation is the recorded-files delivery mode of Speech-to-text translation. Submit audio from a public URL or uploaded file, and Soniox processes it as a background job. When the job completes, retrieve the translated transcript from the result; for production workflows, use a webhook to be notified when the translation is ready.

Use it for:

  • Bulk translation pipelines: meeting recordings, podcasts, voicemails, call-center archives.
  • Long files: single jobs handle audio up to 5 hours.
  • Server-to-server workloads that don't need a live WebSocket connection.

Need to translate live audio with low latency instead? See Real-time speech-to-text translation.


How async delivery works

Async speech-to-text translation is the async transcription flow with a translation block added to the request. Once the job finishes, the resulting transcript contains both the original spoken text and its translation, returned as a unified token stream. It is the same shape as real-time delivery, just delivered when the audio is fully processed.


Translation modes

Async speech-to-text translation supports both translation modes. See Translation modes for the full reference.

  • One-way translation: translate detected speech into a single target language. Bulk meeting, call, and podcast translation.
  • Two-way translation: bidirectional between two languages. Bilingual interviews and calls.

See Supported languages for language codes and coverage notes.


Audio input options

Translate from a public URL

If your audio is publicly accessible over HTTPS, pass audio_url:

{ "audio_url": "https://example.com/audio.mp3" }

Translate from a local file

For local files, upload to Soniox first via the Files API, then reference the returned file_id:

{ "file_id": "your_file_id" }

Supported audio formats

Soniox auto-detects formats with no extra configuration:

aac, aiff, amr, asf, flac, mp3, ogg, wav, webm, m4a, mp4

Quickstart

Add a translation block to your async transcription request. The Node SDK also ships a client.stt.translate helper that returns a structured translation result.

{
  "model": "stt-async-v5",
  "audio_url": "https://example.com/audio.mp3",
  "translation": {
    "type": "one_way",
    "target_language": "es"
  }
}

Get notified when a job completes

For long files, prefer webhooks over polling. Provide a webhook_url on the request and Soniox will POST to it as soon as the transcription (and its translation) is ready.

{
  "model": "stt-async-v5",
  "audio_url": "https://example.com/audio.mp3",
  "translation": { "type": "one_way", "target_language": "es" },
  "webhook_url": "https://your-app.example.com/soniox-webhook"
}

See Webhooks for the payload shape, signature verification, and retry behavior.


Limits


Runnable examples

Prerequisite: Complete the steps in Get started.

See on GitHub: soniox_sdk_async.py.

import os
import argparse
from typing import Optional

from soniox import SonioxClient
from soniox.types import (
    CreateTranscriptionConfig,
    StructuredContext,
    TranslationConfig,
    StructuredContextGeneralItem,
    StructuredContextTranslationTerm,
)
from soniox.utils import render_tokens


def get_config(translation: Optional[str]) -> CreateTranscriptionConfig:
    config = CreateTranscriptionConfig(
        # Select the model to use.
        # See: docs.soniox.com/stt/models
        model="stt-async-v5",
        #
        # Set language hints when possible to significantly improve accuracy.
        # See: docs.soniox.com/stt/concepts/language-hints
        language_hints=["en", "es"],
        #
        # Enable language identification. Each token will include a "language" field.
        # See: docs.soniox.com/stt/concepts/language-identification
        enable_language_identification=True,
        #
        # Enable speaker diarization. Each token will include a "speaker" field.
        # See: docs.soniox.com/stt/concepts/speaker-diarization
        enable_speaker_diarization=True,
        #
        # Set context to help the model understand your domain, recognize important terms,
        # and apply custom vocabulary and translation preferences.
        # See: docs.soniox.com/stt/concepts/context
        context=StructuredContext(
            general=[
                StructuredContextGeneralItem(key="domain", value="Healthcare"),
                StructuredContextGeneralItem(
                    key="topic", value="Diabetes management consultation"
                ),
                StructuredContextGeneralItem(key="doctor", value="Dr. Martha Smith"),
                StructuredContextGeneralItem(key="patient", value="Mr. David Miller"),
                StructuredContextGeneralItem(
                    key="organization", value="St John's Hospital"
                ),
            ],
            text="Mr. David Miller visited his healthcare provider last month for a routine follow-up related to diabetes care. The clinician reviewed his recent test results, noted improved glucose levels, and adjusted his medication schedule accordingly. They also discussed meal planning strategies and scheduled the next check-up for early spring.",
            terms=[
                "Celebrex",
                "Zyrtec",
                "Xanax",
                "Prilosec",
                "Amoxicillin Clavulanate Potassium",
            ],
            translation_terms=[
                StructuredContextTranslationTerm(
                    source="Mr. Smith", target="Sr. Smith"
                ),
                StructuredContextTranslationTerm(
                    source="St John's", target="St John's"
                ),
                StructuredContextTranslationTerm(source="stroke", target="ictus"),
            ],
        ),
        #
        # Optional identifier to track this request (client-defined).
        # See: https://docs.soniox.com/stt/api-reference/transcriptions/create_transcription#request
        client_reference_id="MyReferenceId",
    )

    # Webhook.
    # You can set a webhook to get notified when the transcription finishes or fails.
    # See: https://docs.soniox.com/stt/api-reference/transcriptions/create_transcription#request
    # In SDK you can set the following fields:
    # - config.webhook_url
    # - config.webhook_auth_header_name
    # - config.webhook_auth_header_value

    # Translation options.
    # See: docs.soniox.com/translation/stt-translation#translation-modes
    if translation == "none":
        pass
    elif translation == "one_way":
        # Translates all languages into the target language.
        config.translation = TranslationConfig(
            type="one_way",
            target_language="es",
        )
    elif translation == "two_way":
        # Translates from language_a to language_b and back from language_b to language_a.
        config.translation = TranslationConfig(
            type="two_way",
            language_a="en",
            language_b="es",
        )
    else:
        raise ValueError(f"Unsupported translation: {translation}")

    return config


def transcribe_file(
    client: SonioxClient,
    audio_url: Optional[str],
    audio_path: Optional[str],
    translation: Optional[str],
) -> None:
    if audio_url is not None:
        # Public URL of the audio file to transcribe.
        assert audio_path is None
        file = None
    elif audio_path is not None:
        # Local file to be uploaded to obtain file id.
        assert audio_url is None
        file = client.files.upload(audio_path)
    else:
        raise ValueError("Missing audio: audio_url or audio_path must be specified.")

    config = get_config(translation)

    print("Creating transcription...")
    transcription = client.stt.create(
        config=config, file_id=file.id if file else None, audio_url=audio_url
    )
    print("Waiting for transcription...")
    client.stt.wait(transcription.id)

    result = client.stt.get_transcript(transcription.id)

    print(render_tokens(result.tokens, []))

    client.stt.delete(transcription.id)

    if file is not None:
        client.files.delete(file.id)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--audio_url", help="Public URL of the audio file to transcribe."
    )
    parser.add_argument(
        "--audio_path", help="Path to a local audio file to transcribe."
    )
    parser.add_argument("--delete_all_files", action="store_true")
    parser.add_argument("--delete_all_transcriptions", action="store_true")
    parser.add_argument("--translation", default="none")
    args = parser.parse_args()

    api_key = os.environ.get("SONIOX_API_KEY")
    if not api_key:
        raise RuntimeError(
            "Missing SONIOX_API_KEY.\n"
            "1. Get your API key at https://console.soniox.com\n"
            "2. Run: export SONIOX_API_KEY=<YOUR_API_KEY>"
        )

    client = SonioxClient()

    # Delete all uploaded files.
    if args.delete_all_files:
        print("Deleting all files...")
        client.files.delete_all()
        return

    # Delete all transcriptions.
    if args.delete_all_transcriptions:
        print("Deleting all transcriptions...")
        client.stt.delete_all()
        return

    # If not deleting, require one audio source.
    if not (args.audio_url or args.audio_path):
        parser.error("Provide --audio_url or --audio_path (or use a delete flag).")

    transcribe_file(client, args.audio_url, args.audio_path, args.translation)


if __name__ == "__main__":
    main()

Terminal
# One-way translation of a local file
python soniox_sdk_async.py --audio_path ../assets/coffee_shop.mp3 --translation one_way

# Two-way translation of a local file
python soniox_sdk_async.py --audio_path ../assets/two_way_translation.mp3 --translation two_way

On this page