Overview
The Speech-to-Text API transcribes an audio file to text in a single synchronous request. Upload audio, get back the transcript in the same response.
POST /api/stt/transcribe/Billed per second of audio. Pairs with the Text to Speech endpoint.
Authentication
Send your key in the x-api-key header (browser sessions may use a JWT
Authorization: Bearer <token> instead). See API Keys
to create one.
x-api-key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxTranscribe audio
POST /api/stt/transcribe/Send the audio as multipart/form-data.
curl -X POST https://api.oshara.ai/api/stt/transcribe/ \
-H "x-api-key: $OSHARA_KEY" \
-F "file=@recording.wav" \
-F "model=whisper" \
-F "language=en"Request fields
| Field | Type | Required | Description |
|---|---|---|---|
file | file | ✓ | The audio file to transcribe. Max 50 MB. |
model | string | whisper (default) or omnilingual. Any other value falls back to whisper. | |
language | string | en (default) or ne (Nepali). |
Models
| Model | Best for |
|---|---|
whisper | General transcription; strong Nepali support (default). |
omnilingual | Broad multilingual coverage (alias: sherpa). |
Response
Returns JSON with the transcript:
{
"success": true,
"message": "Request successful",
"data": {
"transcript": "…transcribed text…",
"model": "whisper",
"language": "en"
}
}Billing
Charged per second of audio (rounded up, with a minimum). Duration is measured from the uploaded file.
Errors
| Status | Meaning |
|---|---|
400 | No file provided, or the file exceeds the 50 MB limit. |
401 | Missing or invalid x-api-key. |
502 | Transcription failed upstream. |
{ "success": false, "message": "An error occurred",
"errors": { "error": "..." } }Live transcription (WebSocket)
For streaming microphone or telephony audio, open a WebSocket and receive transcript fragments as the audio arrives, instead of waiting for a whole file.
wss://api.oshara.ai/ws/stt/live_transcribe?model=whisper&language=enAuthentication
Send your key in the x-api-key handshake header — the same key the HTTP
endpoint takes:
x-api-key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxBrowsers cannot set headers on a WebSocket, so ?api_key=<key> is accepted as a
fallback (browser sessions may pass a JWT as ?token=<jwt> instead).
Prefer the header wherever your client can send one. Query strings are recorded in proxy and access logs, and an API key is a long-lived secret to leave there.
Query parameters
| Param | Description |
|---|---|
model | whisper (default) or omnilingual. |
language | en (default) or ne. |
api_key | API key, when a header can’t be sent. |
Protocol
The socket is accepted only once the model is ready to receive audio — if the handshake succeeds, you can start streaming immediately.
- Send audio as binary frames: 16 kHz mono PCM16 (raw samples, no WAV header).
- Send control frames as JSON text.
{"action":"flush"}forces the model to emit what it has so far. - Receive JSON text frames:
{ "type": "transcript", "text": "…fragment of speech…" }
{ "type": "flushed" }
{ "type": "error", "message": "…" }Example
import asyncio, websockets
URL = "wss://api.oshara.ai/ws/stt/live_transcribe?model=whisper&language=en"
async def main():
async with websockets.connect(
URL, additional_headers={"x-api-key": OSHARA_KEY}
) as ws:
async def send_audio():
for chunk in pcm16_chunks(): # 16 kHz mono PCM16 bytes
await ws.send(chunk)
await ws.send('{"action":"flush"}')
asyncio.create_task(send_audio())
async for message in ws:
print(message)
asyncio.run(main())Close codes
| Code | Meaning |
|---|---|
4401 | Missing or invalid credentials. |
4402 | Insufficient credits. |
1011 | The transcription model could not be reached. |
Billing
Charged per second of audio streamed, totalled and billed when the socket closes.