> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kugelaudio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Types & Errors

> Error classes and the full TypeScript interface reference for the KugelAudio SDK

## Error Handling

```typescript theme={null}
import { KugelAudio } from 'kugelaudio';
import {
  KugelAudioError,
  AuthenticationError,
  RateLimitError,
  InsufficientCreditsError,
  ValidationError,
  NotFoundError,
  ConnectionError,
} from 'kugelaudio';

try {
  const audio = await client.tts.generate({ text: 'Hello!', voiceId: 1071 });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof RateLimitError) {
    console.error('Rate limit exceeded, please wait');
  } else if (error instanceof InsufficientCreditsError) {
    console.error('Not enough credits, please top up');
  } else if (error instanceof NotFoundError) {
    console.error('Voice, model, or dictionary not found');
  } else if (error instanceof ValidationError) {
    console.error(`Invalid request: ${error.message}`);
  } else if (error instanceof ConnectionError) {
    console.error('Failed to connect to server');
  } else if (error instanceof KugelAudioError) {
    console.error(`API error: ${error.message}`);
  }
}
```

All errors extend `KugelAudioError` and carry a machine-readable `code`. The
package also exports the `ErrorCodes` and `WsCloseCodes` constant maps for
matching specific codes when you need finer-grained handling than the classes
above.

## KugelAudioOptions

```typescript theme={null}
type Region = 'eu' | 'us' | 'global';

interface KugelAudioOptions {
  apiKey: string;                   // Required (can be prefixed with 'eu-' for EU)
  isMasterKey?: boolean;            // Treat apiKey as a master key (server-side)
  isToken?: boolean;                // Treat apiKey as a JWT token
  orgId?: number;                   // Org to bill against (token auth)
  region?: Region;                  // 'eu' selects the direct EU endpoint
  apiUrl?: string;                  // Default: https://api.kugelaudio.com
  ttsUrl?: string;                  // Default: same as apiUrl
  timeout?: number;                 // Default: 60000 (ms)
  keepalivePingInterval?: number | null;  // Default: 20000 (ms); 0/null disables
}
```

## GenerateOptions

```typescript theme={null}
interface GenerateOptions {
  text: string;              // Required: Text to synthesize
  modelId?: string;          // Default: 'kugel-3'
  voiceId?: number;          // SDK-optional; required for successful synthesis
  cfgScale?: number;         // Guidance scale 1.2-2.5; default: 2.0
  temperature?: number;      // Sampling variance 0.0-1.0; omit for server default
  maxNewTokens?: number;     // Default: 2048
  sampleRate?: number;       // Default: 24000
  outputFormat?: string;     // 'pcm_24000' | 'ulaw_8000' | 'alaw_8000' | ...
  normalize?: boolean;       // Default: true - Enable text normalization
  language?: string;         // ISO 639-1 code for normalization (e.g., 'en', 'de')
  wordTimestamps?: boolean;  // Default: false - Request word-level timestamps
  speed?: number;            // Playback speed 0.8-1.2 (default 1.0); pitch-preserving
  projectId?: number;        // Project ID for dictionary lookup (all auth modes)
  dictionaryIds?: number[];  // With projectId: omit = all active, [] = none,
                             // list = exact IDs (including inactive ones)
}
```

<Note>
  Using `normalize: true` without `language` may cause incorrect normalizations. Always specify `language` when you know it.
</Note>

## AudioChunk

```typescript theme={null}
interface AudioChunk {
  audio: string;       // Base64-encoded bytes in `encoding`
  encoding: 'pcm_s16le' | 'mulaw' | 'alaw'; // G.711 when outputFormat is set
  index: number;       // Chunk index (0-based)
  sampleRate: number;  // Requested sample rate (24000 by default)
  samples: number;     // Number of samples in chunk
}
```

## WordTimestamp

```typescript theme={null}
interface WordTimestamp {
  word: string;      // The word
  startMs: number;   // Start time in milliseconds
  endMs: number;     // End time in milliseconds
  charStart: number; // Character start index in original text
  charEnd: number;   // Character end index in original text
  score: number;     // Compatibility field; currently always 1.0
}
```

## AudioResponse

```typescript theme={null}
interface AudioResponse {
  audio: ArrayBuffer;              // Complete bytes in the requested output format
  sampleRate: number;              // Requested sample rate (24000 by default)
  samples: number;                 // Total samples
  durationMs: number;              // Duration in milliseconds
  generationMs: number;            // Generation time in milliseconds
  rtf: number;                     // Real-time factor
  wordTimestamps: WordTimestamp[];  // Per-word timing (when wordTimestamps: true)
}
```

## GenerationStats

```typescript theme={null}
interface GenerationStats {
  final: true;
  chunks: number;         // Number of chunks generated
  totalSamples: number;   // Total samples generated
  durationMs: number;     // Audio duration in ms
  generationMs: number;   // Generation time in ms
  rtf: number;           // Real-time factor
  error?: string;         // Error message when supplied by the final frame
  usage?: SessionUsage;  // Per-request usage (audio time + charge); undefined if not reported
}
```

## SessionUsage

Per-conversation usage for billing your own customers. Available on
`StreamingSession.lastUsage` (per session), `MultiContextSession.usageFor(...)`
and the `onContextClosed` callback (per context), and `GenerationStats.usage`
(per one-shot `stream()` request).

```typescript theme={null}
interface SessionUsage {
  audioSeconds: number;    // Audio generated (the unit we bill on)
  costCents: number | null; // Actual charge in EUR cents; null if undetermined
  currency?: string;       // Currency of costCents ('eur'); set only when costCents is
  characters?: number;     // Input characters; omitted on multi-context per-context usage
  modelId?: string;        // Model that produced the audio
  costAvailable: boolean;  // true when an authoritative charge was returned
}
```

<Note>
  `costCents` is `null` (and `costAvailable` is `false`) when the charge cannot
  be determined at session end — e.g. a transient billing error or an internal
  session. It is never a misleading `0`. `audioSeconds` is always reported.
</Note>

## StreamCallbacks

Used with the one-shot `client.tts.stream()` endpoint:

```typescript theme={null}
interface StreamCallbacks {
  onOpen?: () => void;
  onChunk?: (chunk: AudioChunk) => void;
  onWordTimestamps?: (timestamps: WordTimestamp[]) => void;
  onFinal?: (stats: GenerationStats) => void;
  onError?: (error: Error) => void;
  onClose?: () => void;
}
```

## StreamConfig

Configuration for `client.tts.streamingSession()` (LLM integration endpoint):

```typescript theme={null}
interface StreamConfig {
  voiceId?: number;           // SDK-optional; required before synthesis
  modelId?: string;           // Default: 'kugel-3'
  cfgScale?: number;          // Guidance scale 1.2-2.5; default: 2.0
  temperature?: number;       // Sampling variance 0.0-1.0; omit for server default
  maxNewTokens?: number;
  sampleRate?: number;
  outputFormat?: string;      // Combined codec + rate token
  flushTimeoutMs?: number;
  maxBufferLength?: number;
  normalize?: boolean;
  language?: string;          // ISO 639-1 code — specify to avoid auto-detect latency
  wordTimestamps?: boolean;
  /**
   * Minimum buffer sizes (chars) before each successive chunk is auto-emitted.
   * Smaller = lower TTFA; larger = better prosody context.
   * Default: [5, 80, 150, 250]
   */
  chunkLengthSchedule?: number[];
  /**
   * When true, start generating at the very first clean sentence boundary.
   * Equivalent to ElevenLabs auto_mode=true. Lowest possible TTFA.
   */
  autoMode?: boolean;
  speed?: number;             // Playback speed 0.8-1.2 (default 1.0); pitch-preserving
  dictionaryIds?: number[];   // Per-session dictionary selection (see GenerateOptions)
}
```

## StreamingSessionCallbacks

```typescript theme={null}
interface StreamingSessionCallbacks {
  onChunk?: (chunk: AudioChunk) => void;
  onChunkComplete?: (chunkId: number, audioSeconds: number, genMs: number) => void;
  // End of audio for the turn (ElevenLabs isFinal equivalent) — fires after
  // the last audio frame, right before onSessionClosed. Not on barge-in.
  onFinal?: (totalAudioSeconds: number, totalTextChunks: number, totalAudioChunks: number) => void;
  onSessionClosed?: (totalAudioSeconds: number, totalTextChunks: number, totalAudioChunks: number) => void;
  onGenerationStarted?: (chunkId: number, text: string) => void;
  onWordTimestamps?: (timestamps: WordTimestamp[]) => void;
  onInterrupted?: () => void;
  onError?: (error: Error) => void;
}
```

## Model

```typescript theme={null}
interface Model {
  id: string;             // e.g. 'kugel-3'
  name: string;           // Human-readable name
  description: string;    // Model description
  parameters: string;     // Parameter-count label (e.g. '7B')
  maxInputLength: number; // Maximum input characters
  sampleRate: number;     // Output sample rate
}
```

## VoiceListResponse

Paginated response from `voices.list()`:

```typescript theme={null}
interface VoiceListResponse {
  voices: Voice[];   // Voices on this page
  total: number;     // Total number of matching voices
  limit: number;     // Page size used
  offset: number;    // Offset used
}
```

## Voice

```typescript theme={null}
type VoiceCategory = 'premade' | 'cloned' | 'designed' | 'conversational' | 'narrative' | 'narrative_story' | 'characters';
type VoiceSex = 'male' | 'female' | 'neutral';
type VoiceAge = 'young' | 'middle_aged' | 'old';
type VoiceQuality = 'low' | 'mid' | 'high';

interface Voice {
  id: number;                    // Voice ID
  name: string;                  // Voice name
  description?: string;          // Description
  category?: VoiceCategory;
  sex?: VoiceSex;
  age?: VoiceAge;
  quality?: string;
  supportedLanguages: string[];  // ['en', 'de', ...]
  sampleText?: string;           // Text used for sample generation
  avatarUrl?: string;            // Avatar image URL
  sampleUrl?: string;            // Sample audio URL
  isPublic: boolean;
  verified: boolean;
}
```

<Warning>
  `VoiceCategory` and `VoiceAge` are legacy SDK declarations, not the API's
  current write-value set. The API can return newer category strings and uses
  `middle_age` (not the declared `middle_aged`); the JavaScript mapper does not
  transform those values, so runtime data can fall outside these unions. Use
  the [Voice API reference](/api-reference/endpoints/voices) for accepted
  create/update values.
</Warning>

## VoiceDetail

Extended voice information returned by `create`, `update`, `get`, and `publish`:

```typescript theme={null}
interface VoiceDetail {
  id: number;
  name: string;
  description: string;
  generativeVoiceDescription: string;
  supportedLanguages: string[];
  category: string;
  age?: string;
  sex?: string;
  quality: string;                 // 'low' | 'mid' | 'high'
  isPublic: boolean;
  verified: boolean;
  pendingVerification: boolean;
  sampleUrl?: string;
  avatarUrl?: string;
  sampleText: string;
}
```

## VoiceReference

```typescript theme={null}
interface VoiceReference {
  id: number;
  voiceId: number;
  name: string;
  referenceText: string;
  s3Path: string;
  audioUrl?: string;
  isGenerated: boolean;
}
```

## CreateVoiceOptions

```typescript theme={null}
interface CreateVoiceOptions {
  name: string;
  sex: string;
  description?: string;
  category?: string;
  age?: string;
  quality?: string;
  supportedLanguages?: string[];
  isPublic?: boolean;
  sampleText?: string;
  referenceFiles?: Array<File | Blob>;
}
```

## UpdateVoiceOptions

```typescript theme={null}
interface UpdateVoiceOptions {
  name?: string;
  description?: string;
  category?: string;
  age?: string;
  sex?: string;
  quality?: string;
  supportedLanguages?: string[];
  isPublic?: boolean;
  sampleText?: string;
}
```

<Note>
  The SDK serializes `isPublic` from `UpdateVoiceOptions`, but the current API
  ignores that field on voice updates. Use `voices.publish()` to make a voice
  public. The API's `generative_voice_description` write field is not exposed
  by `CreateVoiceOptions` or `UpdateVoiceOptions`.
</Note>

***

Dictionary types live on the [Dictionaries](/sdks/javascript/dictionaries#dictionary-types) page; multi-context types live on the [Streaming Sessions](/sdks/javascript/streaming#multi-context-types) page.
