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

Speech Alignment API

Align audio to text using phonetic forced alignment. Upload an audio or video file with a transcript, and receive perfectly timed SRT subtitles. Powered by Sawalign — a phonetic aligner combining wav2vec2 (audio→IPA) with Sawtone (text→IPA) and CTC Viterbi forced alignment.

How It Works

  1. Upload your audio/video file along with the transcript text
  2. Audio is denoised using spectral-gated noise reduction
  3. The text is phonetically encoded using the Sawtone IPA model
  4. Audio is phonetically decoded using wav2vec2-xlsr-53-espeak-cv-ft
  5. CTC Viterbi forced alignment matches audio frames to text tokens
  6. Smart segmentation groups words into subtitle lines by pauses
  7. An SRT file is generated with precise timestamps

Endpoint

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

This is an asynchronous endpoint — it returns a job ID immediately. Poll for status and download the result when done.

Step 1: Submit Alignment Job

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

ParameterTypeRequiredDescription
audiofileYesAudio or video file (wav, mp3, flac, mp4, mov, mkv, etc.)
textstringYesTranscript text (plain text or SRT format — timestamps are stripped automatically)

Size limits:

  • Audio: up to 128 MB
  • Text: up to 1 MB

Example — curl

bash
curl -X POST https://api.sawalni.com/v1/speech/align \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "audio=@my_recording.wav" \ -F "text=Hello everyone, welcome to the presentation. Today we will cover three main topics."

Response (HTTP 202 Accepted)

json
{ "job_id": "a1b2c3d4e5f67890", "status": "pending", "message": "Alignment job queued. Poll /v1/speech/align/job/{job_id} for status.", "usage": { "audio_bytes": 1567890, "text_bytes": 82 } }

Step 2: Poll Job Status

text
GET https://api.sawalni.com/v1/speech/align/job/{job_id}

Response — Processing (with Partial Results)

The status response includes progress (0.0–1.0) and words_so_far (partial list of aligned words) to enable streaming UI.

json
{ "job_id": "a1b2c3d4e5f67890", "status": "processing", "step": "Aligning audio to text...", "progress": 0.42, "words_so_far": [ { "word": "Hello", "index": 0, "start": 0.32, "end": 0.68 }, { "word": "everyone", "index": 1, "start": 0.72, "end": 1.24 } ], "usage": { "audio_bytes": 1567890, "text_bytes": 82 } }

Response — Done

json
{ "job_id": "a1b2c3d4e5f67890", "status": "done", "step": "Alignment complete", "srt_url": "/v1/speech/align/job/a1b2c3d4e5f67890/srt", "usage": { "audio_bytes": 1567890, "text_bytes": 82 } }

Step 3: Download SRT

text
GET https://api.sawalni.com/v1/speech/align/job/{job_id}/srt

Returns the SRT file as text/plain. Example output:

text
1 00:00:00,320 --> 00:00:02,840 Hello everyone, welcome to the presentation. 2 00:00:03,200 --> 00:00:05,760 Today we will cover three main topics.

Full Example — Python

python
import requests import time API_KEY = "YOUR_API_KEY" BASE = "https://api.sawalni.com/v1" headers = {"Authorization": f"Bearer {API_KEY}"} # Step 1: Submit alignment with open("recording.wav", "rb") as f: resp = requests.post( f"{BASE}/speech/align", headers=headers, files={"audio": ("recording.wav", f, "audio/wav")}, data={"text": open("transcript.txt").read()}, ) resp.raise_for_status() job_id = resp.json()["job_id"] print(f"Job submitted: {job_id}") # Step 2: Poll until done while True: status = requests.get( f"{BASE}/speech/align/job/{job_id}", headers=headers, ).json() print(f" Status: {status['status']} — {status.get('step', '')}") if status["status"] == "done": break if status["status"] == "error": raise Exception(status.get("error", "Unknown error")) time.sleep(2) # Step 3: Download SRT srt = requests.get( f"{BASE}/speech/align/job/{job_id}/srt", headers=headers, ).text with open("output.srt", "w") as f: f.write(srt) print(f"Saved output.srt ({len(srt)} bytes)")

Full Example — JavaScript

javascript
const API_KEY = 'YOUR_API_KEY'; const BASE = 'https://api.sawalni.com/v1'; const headers = { 'Authorization': `Bearer ${API_KEY}` }; // Step 1: Submit const form = new FormData(); form.append('audio', audioFile); // File or Blob form.append('text', transcriptText); // string const submitRes = await fetch(`${BASE}/speech/align`, { method: 'POST', headers, body: form, }); const { job_id } = await submitRes.json(); // Step 2: Poll let status; do { await new Promise(r => setTimeout(r, 2000)); const res = await fetch(`${BASE}/speech/align/job/${job_id}`, { headers }); status = await res.json(); console.log(status.status, status.step); } while (status.status === 'pending' || status.status === 'processing'); if (status.status === 'error') throw new Error(status.error); // Step 3: Download SRT const srt = await (await fetch(`${BASE}/speech/align/job/${job_id}/srt`, { headers })).text(); console.log(srt);

Accepted Text Formats

The text parameter accepts multiple formats — the server auto-detects:

FormatExampleBehavior
Plain textHello world. This is a test.Split by sentences/lines
Line-per-sentenceLine 1\nLine 2\nLine 3Each line becomes a segment
SRT formatFull SRT with timestampsTimestamps stripped, text extracted

Supported Audio Formats

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

Audio is automatically converted to 16kHz mono WAV and denoised before alignment.

Job Lifecycle

StatusMeaning
pendingQueued, waiting for processing
processingActively being aligned
doneComplete — SRT available for download
errorFailed — check error field for details

Jobs and their files are retained for 24 hours after completion, then automatically cleaned up.

Error Handling

HTTP CodeMeaning
202Job accepted and queued
400Invalid input (unsupported format, empty text, file too large)
404Job not found
409Job not yet complete (returned for SRT download on pending/processing jobs)
413Audio file exceeds 128 MB limit
422Job failed — check the error detail

Pricing

Speech alignment is metered by audio file size (bytes uploaded).

MetricRate
Audio bytes0.1 credits per 1 MB

Example: a 10 MB audio file costs 1.0 credits.

Tips

  • Client-side extraction: For video files, extract audio in the browser before uploading to avoid sending large video data. The playground does this automatically.
  • SRT input: If you already have subtitles but the timing is off, paste the SRT — timestamps will be stripped and re-computed from the audio.
  • Segmentation: The aligner automatically segments text at speech pauses. For best results, provide clean sentence-level text.
  • Language support: Works with any language supported by the wav2vec2-xlsr-53 model (100+ languages). Arabic, English, French, German, Spanish, and many more.