Soniox
Docs
Core concepts

Async transcription

Learn about async transcription for audio files.

Overview

Soniox supports asynchronous transcription for audio files, allowing you to transcribe content without needing a live connection or streaming pipeline. You can submit audio from a public URL or by uploading a local file to the Soniox Files API.

Once submitted, transcription jobs are processed in the background and can be polled for status and results.


Audio input options

Transcribe from public URL

If your audio is hosted at a publicly accessible HTTP URL, you can simply use the audio_url parameter when creating the transcription request.

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

Transcribe from local file

To transcribe a local file, follow these steps:

  1. Upload the file using the Files API.
  2. Use the returned file id when creating the transcription request.
{
  "file_id": file_id
}

Files API endpoints

EndpointDescription
POST /v1/filesUpload file — Uploads a local file
GET /v1/files/{id}Get file — Returns metadata for a specific file
GET /v1/filesList files — Lists all uploaded files
DELETE /v1/files/{id}Delete file — Deletes a specific file

Limits

Limit TypeValue
Total file size (GB)10
Total number of files1,000

These limits can be increased in the Soniox Console upon request.


Transcriptions API endpoints

EndpointDescription
POST /v1/transcriptionsCreate transcription — Submits a transcription job
GET /v1/transcriptions/{id}Get transcription — Returns metadata for a job
GET /v1/transcriptions/{id}/transcriptGet transcript — Returns the actual transcription result
GET /v1/transcriptionsList transcriptions — Lists all transcription jobs
DELETE /v1/transcriptions/{id}Delete transcription — Deletes a specific transcription job

Limits

Limit TypeValue
Total transcriptions2,000
Pending transcriptions100

These limits can be increased in the Soniox Console upon request.


Best practices

  • Delete uploaded files once transcription is completed and no longer needed.
  • Delete transcription jobs after retrieving the results to avoid hitting quota limits.

Examples

Transcribe a file from URL

Demonstrates how to create an asynchronous transcription job using a publicly accessible audio URL. No upload step is required — simply pass the URL in the audio_url parameter of the transcription request.

This is the easiest way to transcribe hosted audio content.

import os
import time
 
import requests
 
# Retrieve the API key from environment variable (ensure SONIOX_API_KEY is set)
api_key = os.environ["SONIOX_API_KEY"]
api_base = "https://api.soniox.com"
audio_url = "https://soniox.com/media/examples/coffee_shop.mp3"
 
session = requests.Session()
session.headers["Authorization"] = f"Bearer {api_key}"
 
 
def poll_until_complete(transcription_id):
    while True:
        res = session.get(f"{api_base}/v1/transcriptions/{transcription_id}")
        res.raise_for_status()
        data = res.json()
        if data["status"] == "completed":
            return
        elif data["status"] == "error":
            raise Exception(
                f"Transcription failed: {data.get('error_message', 'Unknown error')}"
            )
        time.sleep(1)
 
 
def main():
    print("Starting transcription...")
 
    res = session.post(
        f"{api_base}/v1/transcriptions",
        json={
            "audio_url": audio_url,
            "model": "stt-async-preview",
            "language_hints": ["en", "es"],
        },
    )
    res.raise_for_status()
    transcription_id = res.json()["id"]
    print(f"Transcription ID: {transcription_id}")
 
    poll_until_complete(transcription_id)
 
    # Get the transcript text
    res = session.get(f"{api_base}/v1/transcriptions/{transcription_id}/transcript")
    res.raise_for_status()
    print("Transcript:")
    print(res.json()["text"])
 
    # Delete the transcription
    res = session.delete(f"{api_base}/v1/transcriptions/{transcription_id}")
    res.raise_for_status()
 
 
if __name__ == "__main__":
    main()

View example on GitHub

Output:


Transcribe a file from disk

Covers how to transcribe audio from a local file by first uploading it to Soniox using the Files API. After uploading, use the returned file id in your transcription request.

This approach is ideal for files not accessible via a public URL.

Download coffee_shop.mp3

Make sure you run this code from the directory that contains your audio file or update the file path to the correct location.

import os
import time
 
import requests
 
# Retrieve the API key from environment variable (ensure SONIOX_API_KEY is set)
api_key = os.environ["SONIOX_API_KEY"]
api_base = "https://api.soniox.com"
file_to_transcribe = "coffee_shop.mp3"
 
session = requests.Session()
session.headers["Authorization"] = f"Bearer {api_key}"
 
 
def poll_until_complete(transcription_id):
    while True:
        res = session.get(f"{api_base}/v1/transcriptions/{transcription_id}")
        res.raise_for_status()
        data = res.json()
        if data["status"] == "completed":
            return
        elif data["status"] == "error":
            raise Exception(
                f"Transcription failed: {data.get('error_message', 'Unknown error')}"
            )
        time.sleep(1)
 
 
def main():
    print("Starting file upload...")
 
    res = session.post(
        f"{api_base}/v1/files",
        files={
            "file": open(file_to_transcribe, "rb"),
        },
    )
    file_id = res.json()["id"]
    print(f"File ID: {file_id}")
 
    print("Starting transcription...")
 
    res = session.post(
        f"{api_base}/v1/transcriptions",
        json={
            "file_id": file_id,
            "model": "stt-async-preview",
            "language_hints": ["en", "es"],
        },
    )
    res.raise_for_status()
    transcription_id = res.json()["id"]
    print(f"Transcription ID: {transcription_id}")
 
    poll_until_complete(transcription_id)
 
    # Get the transcript text
    res = session.get(f"{api_base}/v1/transcriptions/{transcription_id}/transcript")
    res.raise_for_status()
    print("Transcript:")
    print(res.json()["text"])
 
    # Delete the transcription
    res = session.delete(f"{api_base}/v1/transcriptions/{transcription_id}")
    res.raise_for_status()
 
    # Delete the file
    res = session.delete(f"{api_base}/v1/files/{file_id}")
    res.raise_for_status()
 
 
if __name__ == "__main__":
    main()
View example on GitHub

Output


Delete all files

Deletes all uploaded files from your organization.

import os
 
import requests
 
# Retrieve the API key from environment variable (ensure SONIOX_API_KEY is set)
api_key = os.environ["SONIOX_API_KEY"]
api_base = "https://api.soniox.com"
 
session = requests.Session()
session.headers["Authorization"] = f"Bearer {api_key}"
 
 
def main():
    print("Getting all files...")
 
    files = []
    cursor = ""
 
    # Get files endpoint returns max 1000 files so cursor-based pagination is
    # needed to get all files.
    while True:
        print("Getting files...")
 
        res = session.get(f"{api_base}/v1/files?cursor={cursor}")
        res.raise_for_status()
        res_json = res.json()
 
        files.extend(res_json["files"])
 
        cursor = res_json["next_page_cursor"]
 
        if cursor is None:
            break
    
    total = len(files)
 
    if total == 0:
        print("No files found")
        return
 
    print(f"Deleting {total} files...")
 
    for i, file in enumerate(files):
        file_id = file["id"]
 
        print(f"Deleting file: {file_id} ({i + 1}/{total})")
 
        res = session.delete(f"{api_base}/v1/files/{file_id}")
        res.raise_for_status()
 
 
if __name__ == "__main__":
    main()

View example on GitHub


Delete all transcriptions

Deletes all completed transcription jobs from your organization.

import os
 
import requests
 
# Retrieve the API key from environment variable (ensure SONIOX_API_KEY is set)
api_key = os.environ["SONIOX_API_KEY"]
api_base = "https://api.soniox.com"
 
session = requests.Session()
session.headers["Authorization"] = f"Bearer {api_key}"
 
 
def main():
    print("Getting all transcriptions...")
 
    transcriptions = []
    cursor = ""
 
    # Get transcriptions call returns max 1000 transcriptions so cursor-based
    # pagination is needed to get all transcriptions.
    while True:
        print("Getting transcriptions...")
 
        res = session.get(f"{api_base}/v1/transcriptions?cursor={cursor}")
        res.raise_for_status()
        res_json = res.json()
 
        for transcription in res_json["transcriptions"]:
            # Only delete completed transcriptions
            if (
                transcription["status"] == "completed"
                or transcription["status"] == "error"
            ):
                transcriptions.append(transcription)
 
        cursor = res_json["next_page_cursor"]
 
        if cursor is None:
            break
 
    total = len(transcriptions)
 
    if total == 0:
        print("No transcriptions found")
        return
 
    print(f"Deleting {total} transcriptions...")
 
    for i, transcription in enumerate(transcriptions):
        transcription_id = transcription["id"]
 
        print(f"Deleting transcription: {transcription_id} ({i + 1}/{total})")
 
        res = session.delete(f"{api_base}/v1/transcriptions/{transcription_id}")
        res.raise_for_status()
 
 
if __name__ == "__main__":
    main()

View example on GitHub

On this page