Kitta AI Docs
Kitta Audio CLI

Node.js SDK

Generate speech, wait and save an audio file with the server-side SDK.

Requires Node.js 22+, an account API key and sufficient API quota. Use on the server; never expose long-lived keys in browser code.

npm install @kittaai/audio-sdk

Complete generation and file saving

Save this as generate-speech.mjs. Inject KITTA_API_KEY through your runtime; the SDK does not automatically use CLI keyring credentials. This code is synchronized from the standalone repository example.

import { lstat, writeFile } from 'node:fs/promises';
import { KittaClient, KittaError } from '@kittaai/audio-sdk';

const [voiceId, idempotencyKey, output = 'hello.mp3'] = process.argv.slice(2);
if (!voiceId || !idempotencyKey || !process.env.KITTA_API_KEY) {
  throw new Error(
    'Set KITTA_API_KEY, then run: node generate-speech.mjs VOICE_ID BUSINESS_OPERATION_KEY [output.mp3]',
  );
}
try {
  await lstat(output);
  throw new Error('Output already exists; choose a new filename. No request was submitted.');
} catch (error) {
  if (error.code !== 'ENOENT') throw error;
}

const client = new KittaClient({
  origin: 'https://kittaai.com',
  apiKey: process.env.KITTA_API_KEY,
});
let taskId;
try {
  const created = await client.createTts(
    { voiceId, text: 'Hello from Kitta', format: 'mp3' },
    { idempotencyKey },
  );
  taskId = created.data.task.taskId;
  console.error(JSON.stringify({ taskId }));
  await client.waitTts(taskId);
  const audio = await client.request('getHttpTtsV3JobAudio', { jobId: taskId });
  if (!(audio.data instanceof Response)) throw new Error('Expected an audio response.');
  const bytes = Buffer.from(await audio.data.arrayBuffer());
  if (bytes.length === 0) throw new Error('The audio response was empty.');
  await writeFile(output, bytes, { flag: 'wx' });
  console.log(JSON.stringify({ taskId, output, bytes: bytes.length }));
} catch (error) {
  console.error(
    JSON.stringify({
      code: error instanceof KittaError ? error.code : 'LOCAL_ERROR',
      taskId: error instanceof KittaError ? (error.taskId ?? taskId) : taskId,
      requestId: error instanceof KittaError ? error.requestId : undefined,
      message:
        'Keep the original operation key and task ID. Inspect the task before creating another paid request.',
    }),
  );
  process.exitCode = 1;
}
node generate-speech.mjs VOICE_ID BUSINESS_OPERATION_KEY hello.mp3

Replace placeholders with an available voice ID and a business idempotency key retained before submission. On success, hello.mp3 contains audio and stdout reports the file. This short-text example buffers audio before saving; for large files use streaming and a temporary file, then publish without overwriting.

Other audio operations

request uses public API field names, not CLI aliases. These are separate paid operation examples; do not execute all of them just to test an import.

await client.request('createOpenSpeechTranscription', { audio_url: 'https://example.com/recording.wav' });
await client.request('createOpenVoice', { name: 'Narrator', audioFiles: ['sample.wav'], visibility: 'private' });
await client.request('createOpenVoiceDesign', { prompt: 'A calm warm narrator', previewText: 'Hello from Kitta' });

Replace samples with URLs or files you are authorized to process. Consult exported operations and the API schemas in the command reference for exact constraints and responses.

Errors and recovery

The SDK does not persist credentials, idempotency keys or task IDs. Your application must retain the key before submission and save the returned task ID. When the ID is known, recover using getTts, waitTts and the audio endpoint rather than creating another request.

KittaError exposes code, status, requestId and taskId. Reads and idempotent TTS creation retry transient failures; other paid operations do not automatically retry. Stopping a local wait does not cancel the remote task. Default request timeout is 30 seconds; wait timeout is 600 seconds.

Recovery and billing · Command and field reference