API documentation
The Clarion API turns Uzbek speech into punctuated text with word-level timestamps and sound events: files over REST, live audio over WebSocket. It is OpenAI-compatible, so with the OpenAI SDK only base_url changes.
https://api.uzasr.uz/v1Authentication
Send the key in a header with every request.
Keys look like uzasr_live_… and are shown once. Keep yours on the server, never in a browser or client app.
Authorization: Bearer uzasr_live_…Quickstart
Transcribe a file with a single request.
import os from openai import OpenAI client = OpenAI( base_url="https://api.uzasr.uz/v1", api_key=os.environ["UZASR_API_KEY"],) result = client.audio.transcriptions.create( model="uzasr-large", file=open("call.mp3", "rb"), response_format="verbose_json", timestamp_granularities=["word"],)print(result.text)import fs from "node:fs"import OpenAI from "openai" const client = new OpenAI({ baseURL: "https://api.uzasr.uz/v1", apiKey: process.env.UZASR_API_KEY,}) const result = await client.audio.transcriptions.create({ model: "uzasr-large", file: fs.createReadStream("call.mp3"), response_format: "verbose_json", timestamp_granularities: ["word"],})console.log(result.text)Synchronous transcription
Files up to 10 minutes. The response comes back in the same request.
POST/v1/audio/transcriptions
| Parameter | Type | Description |
|---|---|---|
| file | file | Audio or video: wav, mp3, m4a, ogg, flac, mp4, webm. |
| model | string | uzasr-large or uzasr-base, or an exact version. |
| response_format | string | json, text or verbose_json. Defaults to json. |
| timestamp_granularities[] | string | word: word-level timestamps, only with verbose_json. |
| language | string | Optional. Only uz is supported. |
Response format
verbose_json with word-level timestamps and sound events.
| Parameter | Type | Description |
|---|---|---|
| text | string | Punctuated text in Latin script. |
| words[] | object | word, start, end: the word and its boundaries in seconds. |
| segments[] | object | Recording segments with boundaries and text. |
| events[] | object | label, start, end, score. Labels: laughter, applause, music. Ignore unknown labels. |
{ "task": "transcribe", "language": "uz", "duration": 28.0, "text": "Oyoqdagi yechish bilan shunaqa ovoz chiqaradiki, …", "segments": [ { "id": 0, "start": 0.0, "end": 9.8, "text": "Oyoqdagi yechish bilan …" } ], "words": [ { "word": "Oyoqdagi", "start": 0.12, "end": 0.64 } ], "events": [ { "label": "laughter", "start": 2.28, "end": 2.52, "score": 0.557 }, { "label": "applause", "start": 19.28, "end": 21.04, "score": 0.659 } ]}The X-Uzasr-Processing-Seconds header contains pure GPU processing time, excluding queueing and startup.
Async jobs
Files up to 3 hours. Create a job and poll its status.
POST/v1/jobs
GET/v1/jobs/{id}
Retrying with the same Idempotency-Key returns the original job. Statuses: queued, succeeded, failed.
import osimport time import requests API = "https://api.uzasr.uz/v1"headers = {"Authorization": f"Bearer {os.environ['UZASR_API_KEY']}"} job = requests.post( f"{API}/jobs", headers={**headers, "Idempotency-Key": "call-2026-10-21-0042"}, files={"file": open("meeting.mp3", "rb")}, data={"model": "uzasr-large"},).json() while job["status"] == "queued": time.sleep(5) job = requests.get(f"{API}/jobs/{job['id']}", headers=headers).json() print(job["result"]["text"])import { openAsBlob } from "node:fs" const API = "https://api.uzasr.uz/v1"const headers = { Authorization: `Bearer ${process.env.UZASR_API_KEY}` } const form = new FormData()form.append("file", await openAsBlob("meeting.mp3"), "meeting.mp3")form.append("model", "uzasr-large") let job = await fetch(`${API}/jobs`, { method: "POST", headers: { ...headers, "Idempotency-Key": "call-2026-10-21-0042" }, body: form,}).then((res) => res.json()) while (job.status === "queued") { await new Promise((resolve) => setTimeout(resolve, 5000)) const poll = await fetch(`${API}/jobs/${job.id}`, { headers }) job = await poll.json()} console.log(job.result.text)Realtime mode
WebSocket: stream PCM in, receive text events out.
WS/v1/realtime?model=uzasr-large
| Event | Direction | Description |
|---|---|---|
| ready | ← server | Session opened, with the exact model version. |
| partial | ← server | The current phrase. The stable field won't change; the rest may be refined. |
| final | ← server | Phrase finalized after a 0.8 s pause, with punctuation. |
| event | ← server | A sound event, 1–1.5 s after it ends. |
| done | ← server | Session closed, with audio_seconds for billing. |
| binary | → client | PCM s16le, 16 kHz, mono. Recommended frame size: 100 ms. |
| stop | → client | {"type":"stop"}: finalize the last phrase and close the session. |
wss://api.uzasr.uz/v1/realtime?model=uzasr-large ← { "type": "ready" }→ <binary PCM s16le 16 kHz, 100 ms>← { "type": "partial", "utterance": 0, "start": 0.0, "text": "Assalomu alaykum qanday", "stable": "Assalomu alaykum" }← { "type": "final", "utterance": 0, "start": 0.0, "end": 2.4, "text": "Assalomu alaykum, qanday yordam bera olaman?" }→ { "type": "stop" }← { "type": "done", "audio_seconds": 2.9 }Browsers can't send headers over WebSocket: connect from your server and proxy the stream.
Models
An alias always points to the current version.
GET/v1/models
| Model | Parameters | WER | When to use |
|---|---|---|---|
| uzasr-large | 600M | 8.1% | Default, maximum accuracy |
| uzasr-base | 220M | 9.4% | High volumes, lower cost |
Errors
A single OpenAI-compatible format.
| HTTP | code | What happened |
|---|---|---|
| 400 | unsupported_parameter | Unknown form parameter. |
| 400 | unsupported_language | language is set to something other than uz. |
| 400 | audio_unreadable | Couldn't decode the audio. |
| 400 | audio_too_long | The recording exceeds the endpoint limit. Use /v1/jobs. |
| 401 | invalid_api_key | The key is missing, invalid or revoked. |
| 404 | model_not_found | No such model. See GET /v1/models. |
| 413 | file_too_large | The file exceeds the size limit. |
| 429 | concurrency_limit_exceeded | Too many concurrent requests. See Retry-After. |
| 503 | model_unavailable | The model is starting up or under maintenance. Try again in a minute. |
| 504 | timeout | Transcription timed out. For long files, use /v1/jobs. |
{ "error": { "type": "invalid_request_error", "code": "unsupported_language", "message": "Only 'uz' is supported" }}Limits
Default values. Configurable for enterprise customers.
| Limit | Value |
|---|---|
| Synchronous request | up to 10 minutes of audio |
| Async job | up to 3 hours of audio |
| Concurrent requests per key | 8 |
| Realtime session | up to 5 minutes |
| Job result retention | 7 days |
