SDKs & guides / JavaScript SDK
JavaScript SDK
The ZeliSpeech JavaScript SDK is a zero-dependency client for
the ZeliSpeech API — textToSpeech.convert(...) /
.stream(...) plus play / save /
stream helpers. It runs in Node ≥ 18 and in the browser (plain
fetch, no WebSocket needed), with TypeScript definitions included.
The SDK talks the same /v1 API documented throughout the
API reference — identical shapes
to the Python SDK, camelCased.
Install
npm install zelispeechQuickstart
import { ZeliSpeech, play, save, stream } from "zelispeech";
const client = new ZeliSpeech({
baseUrl: "https://voice.zeligate.com",
apiKey: "sk-zeli-...", // optional if the box runs open
});
// 1) Stream — first audio after the first sentence, not the whole passage
const audio = client.textToSpeech.stream("zeli-voice-1", "Hey there, this is Zeli.");
for await (const chunk of audio) {
// mp3 bytes (Uint8Array) as they generate
}
// 2) Stream + play live (Node-only, needs ffplay)
await stream(client.textToSpeech.stream("zeli-voice-1", "Playing as I generate."));
// 3) One-shot — a finished clip
const clip = await client.textToSpeech.convert("zeli-voice-1", "Hello world.");
await save(clip, "hello.mp3");Client
new ZeliSpeech({ baseUrl, apiKey, timeoutMs = 60000 })http://host:8000 or https://voice.zeligate.com;
do not include a trailing /v1.
Sent as an Authorization: Bearer token on every request.
Required only when the box sets ZELI_API_KEY. In the browser,
use an ephemeral
token instead of a real key.
Per-request idle timeout in milliseconds.
await client.capabilities(); // -> { engine, engineLabel, tags, tagList, ... }
await client.health(); // -> { status: "ok", ready: true }
await client.isReady(); // -> booleanSynthesis — client.textToSpeech
client.textToSpeech.stream(voiceId, text, {
modelId = "zeli-turbo", voiceSettings, outputFormat = "mp3_44100_128", timeoutMs,
}) // -> AudioStream
await client.textToSpeech.convert(voiceId, text, { ...same }) // -> Uint8Arraystream(...)returns anAudioStream—for awaitit for encodedUint8Arraychunks;await audio.read()drains it to one blob. It exposes.outputFormat,.sampleRate,.voice, and.requestId.convert(...)returns the finished clip in the requestedoutputFormat— the full menu is in Output formats.voiceSettings(stability/style/speed, snake_cased fields) maps onto Turbo delivery — see Voice settings.
Voices — client.voices
await client.voices.list(); // -> Voice[]
await client.voices.get("zeli-voice-1"); // -> Voice (404s on unknown ids)
await client.voices.add({ name, file, description }); // zero-shot clone -> Voice
await client.voices.delete("custom-…");file may be a path (Node), a Blob/File, a Uint8Array, or an
ArrayBuffer. ~10–20 s of clean single-speaker audio works best.
Ephemeral tokens — client.tokens
// backend only — requires a FULL api key
const { token, expires_at } = await client.tokens.createEphemeral({ ttlSeconds: 300 });Mints a short-lived, synthesis-only zsk_temp_… token to hand to a browser —
see Authentication → Ephemeral tokens
for the full flow.
Audio helpers
await save(bytes, path); // write to disk (Node-only; pcm_* wrapped when .wav)
await play(clip); // system player: afplay / ffplay / aplay (Node-only)
await stream(audioStream); // play chunks live via ffplay; returns the bytes (Node-only)
pcmToWav(pcm, sampleRate); // wrap raw PCM in a WAV container (works everywhere)In the browser, build a blob and play it instead:
const clip = await client.textToSpeech.convert("zeli-voice-1", "Hi!");
new Audio(URL.createObjectURL(new Blob([clip], { type: "audio/mpeg" }))).play();Errors
All derive from ZeliSpeechError:
| Exception | When |
|---|---|
ConfigurationError | bad baseUrl, or a missing player |
ConnectionError | server unreachable (refused / DNS / timeout) |
APIError | non-2xx from an HTTP endpoint (.statusCode, .status, .body) |
GenerationError | the stream broke mid-synthesis |
Auth failures surface as APIError with .status of missing_api_key,
invalid_api_key, or insufficient_scope (ephemeral token on a management
route).