Skip to content
API Reference · v1

Build with Audexum.

REST API. Bearer auth. JSON in, WAV/MP3/OGG/Opus out. Streaming and webhooks included.


Authentication

Generate an API key from your dashboard. Send it as a Bearer token on every request.

http
Authorization: Bearer sk_live_•••••••••••••••••••••••••••••••••
POST /api/synthesize

Generate audio from text. Returns audio/wav by default (44.1 kHz, 16-bit PCM, mono). Use format for MP3/OGG/Opus, or stream=true for low-latency chunked streaming.

curl
curl -X POST https://audexum.com/api/synthesize \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Hello world",
    "voice": "M1",
    "lang": "en",
    "speed": 1.05,
    "steps": 8
  }' \
  --output hello.wav

Request body

FieldTypeDefaultNotes
textstringrequiredUp to ~5,000 characters per call.
voiceF1..F5, M1..M5M1Five female, five male voices.
langen, bg, ko, ja, ar, de, …en33 supported. See /api/voices.
speed0.5–2.01.05Playback rate.
steps4–168Diffusion steps. More = higher quality, slower.
formatwav | mp3 | ogg | opuswavOutput format. Quota is identical across formats.
streambooleanfalseStream chunked WAV. Only format=wav supported with stream=true.
backendsupertonic | kokorosupertonicTTS engine to use.

Response headers

FieldTypeDefaultNotes
Content-Typestringaudio/wav · audio/mpeg · audio/ogg · audio/opus
X-Gen-Time-MsintWall-clock generation time, ms.
X-Audio-Duration-SfloatOutput audio duration, seconds.
X-RTFfloatAudio / generation ratio. >1 = faster than real-time.
X-FormatstringEcho of requested format.
X-Stream1Present when stream=true; body is concatenated WAV chunks.
Output formats (OGG / Opus / MP3)

Add "format": "ogg" (or mp3 / opus) to get a transcoded response. Quota is identical regardless of format. The AudioSeal watermark survives MP3 encoding.

curl
# OGG/Opus — smallest file size, best for streaming/web
curl -X POST https://audexum.com/api/synthesize \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello", "voice": "M1", "lang": "en", "format": "ogg"}' \
  --output hello.ogg

# MP3 — maximum compatibility
curl -X POST https://audexum.com/api/synthesize \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello", "voice": "M1", "lang": "en", "format": "mp3"}' \
  --output hello.mp3
python
import requests

r = requests.post(
    "https://audexum.com/api/synthesize",
    headers={"Authorization": "Bearer sk_live_..."},
    json={"text": "Hello world", "voice": "M1", "lang": "en", "format": "ogg"},
)
r.raise_for_status()
with open("hello.ogg", "wb") as f:
    f.write(r.content)
# Content-Type: audio/ogg
formatContent-TypeCodec
wavaudio/wavPCM 16-bit, 44.1 kHz (no transcode)
mp3audio/mpeglibmp3lame VBR ~192 kbps
oggaudio/ogglibopus 96 kbps, 48 kHz
opusaudio/opuslibopus 96 kbps, 48 kHz (Ogg container)
Streaming TTS

Add "stream": true to receive audio as it generates. The response is a chunked-transfer stream of concatenated WAV files — each chunk is a complete, valid WAV (44-byte RIFF header + PCM) so you can begin playback immediately. Quota is reserved for the full text up front, identical to a non-streaming call. Streaming requires format=wav (the default).

curl
curl -X POST https://audexum.com/api/synthesize \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"text": "Sentence one. Sentence two. Sentence three.", "voice": "M1", "lang": "en", "stream": true}' \
  --no-buffer --output - | ffplay -nodisp -i pipe:0
python
import requests

with requests.post(
    "https://audexum.com/api/synthesize",
    headers={"Authorization": "Bearer sk_live_..."},
    json={
        "text": "First sentence. Second sentence. Third one.",
        "voice": "M1",
        "lang": "en",
        "stream": True,
    },
    stream=True,
) as r:
    r.raise_for_status()
    with open("streamed.wav", "wb") as f:
        for chunk in r.iter_content(chunk_size=None):
            f.write(chunk)
# Each yielded chunk is a standalone WAV file (header + PCM).
# Concatenating them produces valid gapless audio.
Streaming notes: text is split on sentence boundaries (~1–3 sentences per chunk). Format must be wav. First-chunk latency is logged server-side. The response header X-Stream: 1 confirms streaming mode.
POST /api/batch

Submit up to 50 texts in one request. Poll for completion, then download a zip.

curl
# submit
curl -X POST https://audexum.com/api/batch \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"texts": ["one", "two"], "voice": "F2", "lang": "en"}'

# poll
curl -H "Authorization: Bearer sk_live_..." \
  https://audexum.com/api/batch/$JOB_ID

# download once status=done
curl -H "Authorization: Bearer sk_live_..." \
  https://audexum.com/api/batch/$JOB_ID/download -O
Webhooks

Configure a webhook endpoint in your Developer settings to receive signed POST notifications. We send JSON with an X-Audexum-Signature header — verify it before processing.

Payload shape

json
{
  "event": "quota.warning_80",
  "data": {
    "monthly_grant": 30000,
    "monthly_used": 24000,
    "monthly_remaining": 6000,
    "overage_enabled": false,
    "plan_tier": "free",
    "period_end": "2026-06-30"
  },
  "timestamp": "2026-06-12T14:22:00.000000+00:00"
}

Events

FieldTypeDefaultNotes
quota.warning_80stringFired when monthly quota crosses 80% used.
quota.exhaustedstringFired when monthly quota is fully consumed.
batch.completedstringFired when a batch job finishes.
audiobook.completedstringFired when an audiobook job finishes.

Signature verification

Every delivery includes X-Audexum-Signature: sha256=<hex> — computed as HMAC-SHA256 over the raw request body using your webhook secret.

python
import hashlib, hmac

def verify_signature(body: bytes, secret: str, sig_header: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, sig_header)

# In your FastAPI/Flask/Django handler:
# body = await request.body()
# sig  = request.headers["X-Audexum-Signature"]
# if not verify_signature(body, WEBHOOK_SECRET, sig):
#     return 401
curl
# Configure endpoint (session auth — browser only)
curl -X PUT https://audexum.com/api/account/webhook \
  -H "Cookie: audexum_session=..." \
  -H "X-Requested-With: XMLHttpRequest" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-server.com/webhooks/audexum"}'
# Response contains secret — store it, shown once only.

# Remove endpoint
curl -X DELETE https://audexum.com/api/account/webhook \
  -H "Cookie: audexum_session=..." \
  -H "X-Requested-With: XMLHttpRequest"
HTTPS endpoints only — HTTP is rejected.
Private/loopback IPs blocked (SSRF protection).
5 s timeout, 2 retries with exponential backoff (1 s, 2 s).
Delivery is fire-and-forget — never blocks a synthesis request.
Errors
CodeMeaning
400Bad request — invalid voice/lang, empty text, or stream+non-wav format
401Missing or invalid API key
402insufficient_credits — Monthly quota exceeded; see /api/usage and /pricing for upgrade options
402feature_gated — Feature requires a higher plan — see error.feature and error.min_tier
422Invalid webhook URL (not HTTPS, private IP, or unresolvable)
429Rate-limited (>50 req/min on the same key)
503Server busy — retry with exponential backoff
Rate limits & fair use
  • Global inflight cap of 50 concurrent synthesis requests
  • Per-key soft limit of 50 requests/minute
  • Per-month character quota from your plan tier
  • Contact us for dedicated capacity or PAYG