API reference
A small REST API. Every response is JSON except /v1/speak, which returns audio.
https://api.kaddu.zaleo.devAuthentication
No key is needed during the preview: anonymous requests are limited per IP address. For longer audio and higher limits, create a key in your account and send it as a bearer token: Authorization: Bearer kd_live_…. Keys have daily quotas that reset at 00:00 UTC.
Limits
| Free (no key) | With a key | |
|---|---|---|
| Audio length | 60 s | 600 s |
| Text length | 500 | 3000 |
| Requests | 30 per 10 min | 600 per 10 min |
| Upload size | 25 MB | |
POST/v1/transcribe
Transcribe an audio file. Send multipart/form-data.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| file | file | yes | The audio file. Any common format; it is converted to 16 kHz mono. |
| language | string | no | ISO 639-3 code, for example wol. Defaults to wol. |
Response
{
"text": "dafa am solo lool",
"language": "wol",
"duration": 3.42,
"model": "…",
"processing_ms": 612
}Examples
curl -X POST https://api.kaddu.zaleo.dev/v1/transcribe \
-F "file=@salaam.wav" \
-F "language=wol"import requests
with open("salaam.wav", "rb") as f:
r = requests.post(
"https://api.kaddu.zaleo.dev/v1/transcribe",
files={"file": f},
data={"language": "wol"},
)
print(r.json()["text"])const form = new FormData();
form.append("file", audioBlob, "salaam.webm");
form.append("language", "wol");
const res = await fetch("https://api.kaddu.zaleo.dev/v1/transcribe", {
method: "POST",
body: form,
});
const { text } = await res.json();POST/v1/transcribe/stream
Same input as /v1/transcribe. Returns newline-delimited JSON: a start line, one line per ~12 s segment as soon as it is transcribed, then a done line with the full text. Use it to show text while long clips are processed.
{"type": "start", "duration": 50.0, "segments": 5, "model": "facebook/mms-1b-all"}
{"type": "segment", "index": 0, "start": 0.0, "end": 10.47, "text": "…"}
…
{"type": "done", "text": "…", "processing_ms": 11800}POST/v1/speak
Synthesise speech. Send JSON, receive audio/wav or audio/mpeg.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| text | string | yes | The text to speak. |
| language | string | yes | ISO 639-3 code, for example wol. |
| format | string | no | wav (default) or mp3. |
Examples
curl -X POST https://api.kaddu.zaleo.dev/v1/speak \
-H "Content-Type: application/json" \
-d '{"text": "Na nga def?", "language": "wol", "format": "mp3"}' \
-o na-nga-def.mp3import requests
r = requests.post(
"https://api.kaddu.zaleo.dev/v1/speak",
json={"text": "Na nga def?", "language": "wol"},
)
open("na-nga-def.wav", "wb").write(r.content)const res = await fetch("https://api.kaddu.zaleo.dev/v1/speak", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: "Na nga def?", language: "wol", format: "mp3" }),
});
const audio = new Audio(URL.createObjectURL(await res.blob()));
audio.play();POST/v1/translate
Translate between Wolof and French. Send JSON, receive JSON.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| text | string | yes | The text to speak. |
| source | string | yes | wol or fra. |
| target | string | yes | fra or wol. |
Examples
curl -X POST https://api.kaddu.zaleo.dev/v1/translate \
-H "Content-Type: application/json" \
-d '{"text": "Na nga def?", "source": "wol", "target": "fra"}'Response
{ "translation": "…", "source": "wol", "target": "fra", "model": "…", "processing_ms": 840 }GET/v1/languages
List languages, their status and which tasks they support.
{
"languages": [
{
"code": "wol",
"name": "Wolof",
"status": "supported",
"stt": { "model": "…", "wer": 0.0 },
"tts": { "model": "…" }
}
],
"limits": { "max_audio_seconds": 60, "max_text_chars": 500 }
}GET /v1/languages also returns speed: the server's measured seconds per audio second (transcribe) and per character (speak, translate), so you can show your own time estimates.
GET/health
Liveness check, with the models currently loaded in memory.
{ "status": "ok", "loaded_models": ["stt:wol"] }Errors
Errors use HTTP status codes and a JSON body with a stable code and a human message. Messages are in English or French, following your Accept-Language header or ?locale=fr.
{
"error": {
"code": "audio_too_long",
"message": "L'audio dure 74.2 s ; la limite est de 60 s pour votre offre."
}
}Common codes
- 400bad_audio · empty_audio · empty_text · bad_format · invalid_request
- 401invalid_key
- 404unsupported_language · unsupported_pair
- 413file_too_large · audio_too_long · text_too_long
- 429rate_limited
- 503busy
Send Accept-Language: fr to get error messages in French.