Sawalni API
APIsDocumentationOpen portal ↗
Omneity Labs API collection ↗Integration quickstart →API keys and playgrounds →
API Reference

Speech Transcription API

Transcribe audio and video files to text using Daktilo, an Arabic-optimized speech recognition model fine-tuned for Arabic dialects.

Endpoint

text
POST https://api.sawalni.com/v1/speech/transcribe

Streaming transcription is available over WebSocket:

text
WS wss://api.sawalni.com/v1/speech/transcribe/stream

Batch mode is recommended for final offline transcription. Streaming mode is designed for live microphone UX and returns partial hypotheses that may revise until the final done event.

Request Body

Send a multipart/form-data request with the audio file and optional parameters.

ParameterTypeRequiredDescription
audiofileYesAudio or video file (wav, mp3, flac, mp4, mov, mkv, etc.)
languagestringNoISO 639-1 language code. Default: ar
modelstringNoModel identifier. Default: daktilo. Compatibility aliases: daktilo-v1, daktilo-v2.

Size limit: Audio files up to 100 MB.

Example — curl

bash
curl -X POST https://api.sawalni.com/v1/speech/transcribe \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "[email protected]" \ -F "language=ar" \ -F "model=daktilo"

Example — Python

python
import requests response = requests.post( "https://api.sawalni.com/v1/speech/transcribe", headers={"Authorization": "Bearer YOUR_API_KEY"}, files={"audio": ("recording.wav", open("recording.wav", "rb"), "audio/wav")}, data={"language": "ar", "model": "daktilo"}, ) result = response.json() print(result["text"]) print(f"Duration: {result['duration']}s")

Example — JavaScript

javascript
const formData = new FormData(); formData.append('audio', audioFile); formData.append('language', 'ar'); formData.append('model', 'daktilo'); const response = await fetch('https://api.sawalni.com/v1/speech/transcribe', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, body: formData, }); const result = await response.json(); console.log(result.text); console.log('Duration:', result.duration, 's');

Streaming WebSocket

Use wss://api.sawalni.com/v1/speech/transcribe/stream for live microphone transcription. The browser authentication path uses WebSocket subprotocols because browsers cannot set an Authorization header on WebSocket connections. Batch mode remains best when you need the most stable offline final transcript.

Client Start Frame

The first client text frame must be JSON:

json
{ "type": "start", "model": "daktilo", "language": "ar", "sample_rate": 16000, "channels": 1, "audio_format": "pcm_s16le" }

After the start frame, send binary frames containing little-endian PCM16 mono audio at 16 kHz. Send {"type":"flush"} to request a partial decode and {"type":"stop"} to finish the stream.

Server Events

EventMeaning
readySession accepted and routed to a Daktilo deployment
partialUnstable live hypothesis, may revise
syncCorrected transcript snapshot emitted during longer streams
finalFinal committed text delta
usageMetering data such as audio seconds and processing milliseconds
doneFinal transcript and usage summary
errorMachine-readable error and detail

Browser Example

javascript
const protocol = 'sawalni.transcribe.v1'; const keyProtocol = 'sawalni-key.' + btoa('YOUR_API_KEY') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, ''); const ws = new WebSocket( 'wss://api.sawalni.com/v1/speech/transcribe/stream', [protocol, keyProtocol] ); ws.onopen = () => { ws.send(JSON.stringify({ type: 'start', model: 'daktilo', language: 'ar', sample_rate: 16000, channels: 1, audio_format: 'pcm_s16le', })); }; ws.onmessage = (event) => { const message = JSON.parse(event.data); if (message.type === 'partial') console.log('partial:', message.text); if (message.type === 'sync') console.log('sync:', message.text); if (message.type === 'final') console.log('final:', message.text_delta); if (message.type === 'done') console.log('done:', message.text); };

Python Example

python
import asyncio import json import wave import websockets async def main(): async with websockets.connect( "wss://api.sawalni.com/v1/speech/transcribe/stream", extra_headers={"Authorization": "Bearer YOUR_API_KEY"}, subprotocols=["sawalni.transcribe.v1"], ) as ws: await ws.send(json.dumps({ "type": "start", "model": "daktilo", "language": "ar", "sample_rate": 16000, "channels": 1, "audio_format": "pcm_s16le", })) with wave.open("recording.wav", "rb") as wav: assert wav.getframerate() == 16000 and wav.getnchannels() == 1 while chunk := wav.readframes(3200): await ws.send(chunk) await ws.send(json.dumps({"type": "stop"})) async for message in ws: print(message) asyncio.run(main())

Close Codes

CodeMeaning
1008Authentication, payment, or entitlement failure
1003Invalid frame or unsupported audio format
1013No healthy deployment capacity; retry shortly
1011Upstream or inference failure

Metering

Streaming transcription is metered by processed audio seconds reported by the backend in usage and done events. Streaming audio blobs are not persisted by the balancer.

Response

json
{ "text": "مرحبا بكم في هذا التسجيل الصوتي", "language": "ar", "model": "daktilo", "duration": 5.76, "usage": { "audio_bytes": 184320, "audio_seconds": 5.76, "processing_ms": 1230.5 } }

Response Fields

FieldTypeDescription
textstringTranscribed text
languagestringLanguage code used for transcription
modelstringModel identifier used
durationnumberAudio duration in seconds
usageobjectMetering data
usage.audio_bytesintegerSize of uploaded audio in bytes
usage.audio_secondsnumberDuration of audio in seconds
usage.processing_msnumberServer-side processing time in milliseconds

Supported Audio Formats

wav, mp3, flac, ogg, m4a, aac, wma, mp4, mov, mkv, avi, webm, m4v

Audio is automatically converted to 16kHz mono WAV via FFmpeg before processing.

Supported Languages

Daktilo supports 90+ languages with specialized optimization for Arabic dialects. Common language codes:

CodeLanguage
arArabic (all dialects)
enEnglish
frFrench
deGerman
esSpanish
itItalian
ptPortuguese
jaJapanese
koKorean
zhChinese
ruRussian
trTurkish
hiHindi

Model Details

PropertyValue
Model IDdaktilo
Aliasesdaktilo-v1, daktilo-v2
SpecializationArabic dialects

Error Handling

HTTP CodeMeaning
200Success — transcription returned
400Empty audio file
413Audio file exceeds 100 MB limit
422Audio conversion failed (unsupported format or corrupted file)
503Model not loaded or no healthy deployments
504Transcription timed out

Pricing

Speech transcription is metered by audio duration (seconds of audio processed).

MetricRate
Audio seconds$6.00 per 1M seconds (~$0.006/min)

This is competitive with major cloud ASR providers while offering specialized Arabic dialect support.

Tips

  • Language hint: Always specify the language parameter for best accuracy. Auto-detection works but explicit language codes produce better results.
  • Audio quality: Cleaner audio produces better transcriptions. Consider noise reduction before uploading.
  • File size: Extract audio from video files client-side before uploading to reduce transfer time.
  • Arabic dialects: Daktilo is specifically fine-tuned for Arabic varieties including MSA, Egyptian, Levantine, Gulf, and Maghrebi dialects.