API Reference

Async Jobs

Live

Create, poll, and download audio for long-running TTS synthesis jobs.

Overview

When you submit text longer than 2,000 characters to the TTS endpoint, it automatically returns a 202 response with a job_id. Use the Jobs API to poll status and download the completed audio.

You can also create jobs explicitly using the endpoint below.

Create job

POST /v1/tts/jobs

Creates an async synthesis job. Returns 202 with job metadata.

bash
curl -X POST https://sauti.finiflowlabs.com/v1/tts/jobs \
  -H "xi-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "A long Swahili text exceeding 2000 characters...",
    "voice_id": "sauti-swahili-v1",
    "voice_settings": {
      "speaking_rate": 1.0,
      "noise_scale": 0.667,
      "noise_scale_duration": 0.8
    }
  }'
json
{
  "job_id": "job_abc123",
  "status": "queued",
  "created_at": "2026-03-15T10:30:00Z"
}

Get job status

GET /v1/tts/jobs/{job_id}

Returns the current status of a job. Status transitions: queuedrunning succeeded or failed.

bash
curl https://sauti.finiflowlabs.com/v1/tts/jobs/job_abc123 \
  -H "xi-api-key: YOUR_KEY"
json
{
  "job_id": "job_abc123",
  "status": "succeeded",
  "created_at": "2026-03-15T10:30:00Z",
  "completed_at": "2026-03-15T10:30:12Z"
}

Download audio

GET /v1/tts/jobs/{job_id}/audio

Downloads the completed audio file. Returns audio/wav binary data. Returns 409 Conflict if the job has not completed yet.

bash
curl https://sauti.finiflowlabs.com/v1/tts/jobs/job_abc123/audio \
  -H "xi-api-key: YOUR_KEY" \
  --output long_speech.wav

Polling example

python
import time
import requests

API_BASE = "https://sauti.finiflowlabs.com"
HEADERS = {"xi-api-key": "YOUR_KEY"}

# 1. Create the job
job = requests.post(
    f"{API_BASE}/v1/tts/jobs",
    headers=HEADERS,
    json={
        "text": "A long Swahili text...",
        "voice_id": "sauti-swahili-v1",
    },
).json()

job_id = job["job_id"]
print(f"Job created: {job_id}")

# 2. Poll until complete
while True:
    status = requests.get(
        f"{API_BASE}/v1/tts/jobs/{job_id}",
        headers=HEADERS,
    ).json()

    if status["status"] in ("succeeded", "failed"):
        break
    print(f"Status: {status['status']}, waiting...")
    time.sleep(2)

# 3. Download audio
if status["status"] == "succeeded":
    audio = requests.get(
        f"{API_BASE}/v1/tts/jobs/{job_id}/audio",
        headers=HEADERS,
    )
    with open("output.wav", "wb") as f:
        f.write(audio.content)
    print("Audio saved.")
else:
    print(f"Job failed: {status}")

Error responses

StatusMeaning
404Job not found
409Job not complete — audio cannot be downloaded yet