Start in sixty seconds¶
export VARTALAAP_API_KEY="vt_live_…" # from https://tts.vartalaap.si/keys
curl -sN -X POST https://api.vartalaap.si/v1/tts \
-H "x-api-key: $VARTALAAP_API_KEY" -H "content-type: application/json" \
-d '{"text":"Callback +44 00000 19024 पर करें।","voice":"saanvi","format":"wav"}' -o emi.wav
import os, requests
r = requests.post("https://api.vartalaap.si/v1/tts", stream=True,
headers={"x-api-key": os.environ["VARTALAAP_API_KEY"]},
json={"text": "Callback +44 00000 19024 पर करें।", "voice": "saanvi", "format": "wav"})
r.raise_for_status()
with open("emi.wav", "wb") as f:
for chunk in r.iter_content(chunk_size=None): # bytes arrive as frames are decoded
f.write(chunk)
const res = await fetch("https://api.vartalaap.si/v1/tts", {
method: "POST",
headers: { "x-api-key": process.env.VARTALAAP_API_KEY, "content-type": "application/json" },
body: JSON.stringify({ text: "Callback +44 00000 19024 पर करें।", voice: "saanvi", format: "wav" }),
});
await pipeline(Readable.fromWeb(res.body), createWriteStream("emi.wav"));
import asyncio, json, os, websockets
async def main():
async with websockets.connect("wss://api.vartalaap.si/v1/tts/stream",
additional_headers={"x-api-key": os.environ["VARTALAAP_API_KEY"]}) as ws:
await ws.send(json.dumps({"text": "Callback +44 00000 19024 पर करें।", "voice": "saanvi", "format": "pcm16"}))
async for msg in ws:
if isinstance(msg, bytes): play(msg) # 16-bit PCM, 24 kHz
elif json.loads(msg)["type"] in ("end", "error"): break
asyncio.run(main())
The response is a WAV stream: the first bytes arrive after the first 80 ms frame is decoded, so a player can start before synthesis finishes. For conversations, open a WebSocket once and send sentences as your LLM produces them; the server tells you the exact moment of first audio.
Build with it¶
QuickstartCreate a key, make the first call with curl, Python, Node or a browser. Streaming guideChunked REST vs WebSocket, the event timeline, buffering, barge-in. API referenceEvery field, status code and event, straight from the server source. Text normalisationWhat the Hinglish normaliser does to numbers, acronyms, dates and OTPs, with 66 canonical cases. VoicesTwenty-one Hinglish, eighteen English (US) and eight English (IN) voices, with samples; how to limit a key to a voice. Voice agentsThe loop, the latency budget, capacity and telephony notes. Limits, errors & 503The retry contract: 503 + Retry-After before any audio, nothing billed. Pricing10 paise per 1,000 characters. What counts, prepaid credits, monthly plans.
How the engine behaves¶
Normalises first. ₹12,450 → बारह हज़ार चार सौ पचास रुपये, EMI → E M I, OTP 482913 digit by digit. Preview it without synthesising.
Chunks on sentences, at most 50 tokens each, and streams chunk after chunk on one connection with a chunk_end event for each.
Caches text prefills per voice and chunk: a repeated IVR line starts in about 18 ms of engine time.
Says no cleanly. When every worker is busy you get 503 with Retry-After, nothing is billed, and you retry. Limits & errors.
Where things live¶
| API | https://api.vartalaap.si, REST and WebSocket, Mumbai |
| Developer portal | tts.vartalaap.si: keys, playground with a live latency waterfall, usage, billing |
| Status | tts.vartalaap.si/status, GET /readyz |
| Changelog | changelog |