A developer tour of the Waridi API
Speech synthesis, recognition, streaming, agents, cloning and dubbing, all from one API. A hands-on walk through the endpoints with curl, Python and Node.
Waridi is in early access, and the API is where most builders will meet us first. This post is a quick tour: what each endpoint does, what a request looks like, and where the sharp edges are today.
One honest caveat up front. During early access, request and response shapes may still change. We will announce breaking changes in the changelog and give notice before we make them. Pin your SDK version and read release notes before upgrading.
The basics
Everything lives under one base URL:
https://api.waridi.io/v1
Requests are authenticated with an API key sent as a bearer token. You get keys from Waridi Studio once your early access account is active. Keep them on your server. Never ship a key inside a mobile app or a web page.
export WARIDI_API_KEY="wr_live_..."
There are two official SDKs. Both wrap the same HTTP API.
pip install waridi
npm install @waridi/sdk
Text to speech: POST /v1/tts
Waridi Sauti turns text into speech. Choose a voice and a model tier. sauti-standard is tuned for speed and cost. sauti-pro is tuned for expressiveness.
curl https://api.waridi.io/v1/tts \
-H "Authorization: Bearer $WARIDI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sauti-standard",
"voice": "amani",
"language": "sw-TZ",
"text": "Karibu! Oda yako itafika kesho asubuhi.",
"format": "mp3"
}' \
--output karibu.mp3
The same call in Python:
from waridi import Waridi
client = Waridi() # reads WARIDI_API_KEY from the environment
audio = client.tts.create(
model="sauti-pro",
voice="amani",
language="sw-TZ",
text="Habari za asubuhi. Malipo yako yamepokelewa.",
format="wav",
)
audio.save("malipo.wav")
Numbers, dates and currency are normalised for you, so "TSh 25,000" is read the way a Tanzanian would say it. If you need control, you can pass hints. For example, you can read a value digit by digit, as you would for a phone number.
Speech to text: POST /v1/stt
Waridi Sikia transcribes recorded audio. The model is sikia-1. It is built for Swahili, regional accents and the Swahili–English mixing people use every day.
import { Waridi } from "@waridi/sdk";
import fs from "node:fs";
const waridi = new Waridi({ apiKey: process.env.WARIDI_API_KEY });
const result = await waridi.stt.create({
model: "sikia-1",
file: fs.createReadStream("call-recording.wav"),
language: "sw",
timestamps: "word",
});
console.log(result.text);
// "Nimejaribu ku-login mara tatu lakini haikubali password."
Notice the transcript keeps the English words the caller used. We do not force everything into one language. If the caller mixed, the transcript mixes too.
Streaming: wss://api.waridi.io/v1/stream
For anything live, from captions to agents, use the WebSocket stream. You send audio frames up and receive partial and final transcripts back. You can also send text and receive synthesised audio frames back.
import asyncio
from waridi import AsyncWaridi
async def main():
client = AsyncWaridi()
async with client.stream.connect(model="sikia-1", sample_rate=16000) as stream:
async for event in stream.transcribe(microphone_frames()):
if event.type == "partial":
print("...", event.text)
elif event.type == "final":
print("✓", event.text)
asyncio.run(main())
Partials arrive while the person is still speaking, so your app can react before they finish. The streaming guide covers frame sizes, endpointing settings and reconnect behaviour.
Agents: POST /v1/agents
Waridi Agents combine Sikia, a language model and Sauti into a voice agent that can hold a phone conversation. You describe the agent, its voice and the tools it may call. We handle the turn-taking.
curl https://api.waridi.io/v1/agents \
-H "Authorization: Bearer $WARIDI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "msaada-wa-wateja",
"voice": "amani",
"language": "sw-TZ",
"instructions": "Wewe ni msaidizi wa huduma kwa wateja. Jibu kwa ufupi na kwa upole.",
"tools": [{ "type": "webhook", "name": "check_balance", "url": "https://example.com/balance" }],
"telephony": { "type": "sip" }
}'
The response includes an agent ID and connection details for SIP or WebRTC. The voice agents docs and the telephony guide explain how to connect a phone number or a browser.
Voice cloning: POST /v1/voices/clone
Cloning creates a custom voice from recordings of a real person. This endpoint will not create a voice without verified consent from the voice owner. The request must reference a completed consent record, which the speaker gives themselves in Waridi Studio by reading a short statement in their own voice.
voice = client.voices.clone(
name="sauti-ya-zuhura",
consent_id="cns_...", # created by the voice owner, not by you
files=[open("sample-1.wav", "rb"), open("sample-2.wav", "rb")],
)
print(voice.id)
If the consent record is missing, expired or revoked, the request fails. That is deliberate. Read voice cloning before building anything on top of it.
Dubbing: POST /v1/dub
Waridi Dub takes a video or audio file and returns a localised version. Long jobs run asynchronously. You get a job ID back and can poll for status or receive a webhook.
const job = await waridi.dub.create({
source_url: "https://example.com/episode-01.mp4",
source_language: "en",
target_language: "sw-TZ",
review: true, // hold the output for human review before final export
});
Errors and limits
Errors come back as JSON with a stable code field. Branch on the code, not the message text. Early access accounts have conservative rate limits. Handle 429 responses with backoff rather than retrying in a tight loop. The errors and rate limits pages list the details.
Start building
The free sandbox gives you enough audio each month to try every endpoint above. The quickstart takes about ten minutes. When you are ready, request early access. We read every message, and early feedback is shaping what this API becomes. Karibu.