> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
title: JavaScript / TypeScript SDK
description: Install and use the Vakyam Node SDK.
---

# JavaScript / TypeScript SDK

The official Node SDK (`@vakyam-ai/tts`) provides a fully typed client for the
public TTS API: voices, speech synthesis, HTTP streaming, and realtime
WebSocket synthesis. Types are generated from the OpenAPI contract.

## Install

```bash
pnpm add @vakyam-ai/tts
```

Requires Node 20+ (for the global `fetch` and Web Streams). In other runtimes,
pass a `fetch` implementation explicitly.

## Create a client

Use `VakyamAI` for regular HTTP calls (`voices.list`, `tts.generate`):

```ts
import { VakyamAI } from "@vakyam-ai/tts";

const client = new VakyamAI({ apiKey: process.env.VAKYAM_API_KEY! });
```

Use `VakyamAIAsync` for HTTP streaming and realtime WebSocket synthesis
(`tts.stream`, `tts.websocket`):

```ts
import { VakyamAIAsync } from "@vakyam-ai/tts";

const asyncClient = new VakyamAIAsync({ apiKey: process.env.VAKYAM_API_KEY! });
```

Options:

| Option                 | Type           | Description                                                     |
| ---------------------- | -------------- | --------------------------------------------------------------- |
| `apiKey`               | `string`       | Required. Your `vak_live_...` key.                              |
| `baseUrl`              | `string`       | Override the API base URL. Defaults to `https://api.vakyam.ai`. |
| `allowInsecureBaseUrl` | `boolean`      | Permit a non-local HTTP base URL. HTTPS is required by default. |
| `timeoutMs`            | `number`       | Request/initial-response timeout in milliseconds.               |
| `fetch`                | `typeof fetch` | Custom fetch implementation for older runtimes.                 |

## List voices

The return type narrows based on `groupBy`:

```ts
const byLanguage = await client.voices.list();                  // VoicesByLanguage
const byVoice = await client.voices.list({ groupBy: "voice" }); // VoicesByVoice
```

## Create speech

```ts
import { writeFile } from "node:fs/promises";

const speech = await client.tts.generate({
  text: "வணக்கம், நான் வாக்யம் AI பேசுகிறேன்.",
  model_id: "raaga-v1",
  voice: "Archana",
  language: "ta-IN",
  output_format: "mp3", // mp3 | wav | pcm | mulaw, default mp3
  sample_rate: 24000,   // 8000 | 16000 | 24000 | 48000, default 24000
  speed: 1.0,           // 0.5 - 2.0, default 1.0
});

await writeFile(`speech.${speech.format}`, speech.audioBytes);
console.log(speech.duration_seconds, speech.characters_used);
```

`output_format`, `sample_rate`, and `speed` are optional and
are also accepted by `tts.stream` and the WebSocket `config`.

> **Note:**
> `voice` accepts a **preset name** (e.g. `"Archana"`) or a **custom voice ID**
> beginning with `vc_` (e.g. `voice: "vc_01EXAMPLE"`).

The response includes every field from the API plus a decoded
`audioBytes: Uint8Array`.

## HTTP streaming

`tts.stream` (on `VakyamAIAsync`) returns an async generator of `Uint8Array`
chunks:

```ts
import { createWriteStream } from "node:fs";

const output = createWriteStream("speech.pcm");

for await (const chunk of asyncClient.tts.stream({
  text: "வணக்கம்.",
  model_id: "raaga-v1",
  voice: "Archana",
  language: "ta-IN",
  output_format: "pcm",
})) {
  output.write(chunk);
}

output.end();
```

You can pass an `AbortSignal` to cancel a request:

```ts
const controller = new AbortController();
const speech = await client.tts.generate(params, { signal: controller.signal });
```

## WebSocket

The session config (model, voice, language, format, speed) is sent **before** any
text — `websocket(...)` opens the connection and sends the `config` message
first, so every `sendText` call after it uses that config.

```ts
import { writeFile } from "node:fs/promises";

// Opens the connection and sends the config message first
const socket = await asyncClient.tts.websocket({
  model_id: "raaga-v1",
  voice: "Archana",
  language: "ta-IN",
  output_format: "pcm",
});

// Then send text — one complete sentence per call
const utterance = await socket.sendText("நான் சரியாக இருக்கிறேன்.");
await writeFile("sentence.pcm", utterance.audioBytes);

socket.close();
```

`sendText` resolves once the full utterance has been received. The returned
object includes `audioBytes`, `audioChunks`, `characters_used`, and
`duration_seconds`.

> **Warning:**
> Wait for the current `sendText` promise to resolve before calling it again. The
> SDK throws if you send another sentence while one is in flight.

### Interrupting an utterance (barge-in)

Call `socket.cancel()` to interrupt the current utterance. It sends a `cancel`,
collects any audio received before the server acknowledges, and resolves with a
`WebSocketCancelledUtterance` (`type: "cancellation"`, plus `audioBytes`,
`audioChunks`, `characters_used`, `duration_seconds`). The session stays open,
and you are billed only for audio produced before the cancel.

```ts
const cancelled = await socket.cancel();
console.log(cancelled.characters_used, cancelled.audioBytes.byteLength);
```

The server closes idle connections after 60 seconds without an incoming message.
By default the SDK sends a JSON `ping` every 30 seconds to keep the session
alive. You can send one manually at any time:

```ts
await socket.ping();
```

Tune or disable the automatic keepalive with `keepAliveIntervalMs`:

```ts
// Custom interval (milliseconds)
const socket = await asyncClient.tts.websocket(
  {
    model_id: "raaga-v1",
    voice: "Archana",
    language: "ta-IN",
    output_format: "pcm",
  },
  { keepAliveIntervalMs: 30000 },
);

// Disable keepalive entirely
const socketNoKeepAlive = await asyncClient.tts.websocket(
  {
    model_id: "raaga-v1",
    voice: "Archana",
    language: "ta-IN",
    output_format: "pcm",
  },
  { keepAliveIntervalMs: false },
);
```

The same options object also accepts `connectionTimeoutMs` (handshake + config
timeout, default `60000`) and `utteranceTimeoutMs` (per-utterance timeout,
default `300000`).

## Error handling

```ts
import {
  VakyamAPIError,
  VakyamValidationError,
  VakyamWebSocketError,
} from "@vakyam-ai/tts";

try {
  await client.tts.generate({
    text: "...",
    model_id: "raaga-v1",
    voice: "Archana",
    language: "ta-IN",
  });
} catch (err) {
  if (err instanceof VakyamValidationError) {
    console.error(err.field, err.message);
  } else if (err instanceof VakyamAPIError) {
    console.error(err.statusCode, err.code, err.message);
  }
}
```

Exported error classes:

* `VakyamError` — base error.
* `VakyamAPIError` — HTTP API errors; exposes `statusCode`, `code`, `message`.
* `VakyamValidationError` — client-side input validation errors; exposes `field`
  and `message`.
* `VakyamWebSocketError` — per-message WebSocket errors; exposes `code` and
  `retryAfterSeconds`.
* `VakyamWebSocketClosedError` — connection closed; exposes `code` and `reason`.

---

*Powered by [holocron.so](https://holocron.so)*
