Documentation Index Fetch the complete documentation index at: https://docs.supertoneapi.com/llms.txt
Use this file to discover all available pages before exploring further.
The official TypeScript SDK is published as @supertone/supertone on npm. Source: supertone-inc/supertone-ts .
Installation
npm add @supertone/supertone
pnpm add @supertone/supertone
bun add @supertone/supertone
Yarn requires installing the peer dependency manually: yarn add @supertone/supertone zod
The package is published with both ESM and CommonJS entry points and ships with TypeScript types. Node 18+ is required (for the global fetch and ReadableStream). Works in Bun and Deno; not designed for the browser (your API key should never live client-side).
Set your API key
export SUPERTONE_API_KEY = "Kp9mZ3xQ7v..."
import { Supertone } from "@supertone/supertone" ;
const client = new Supertone ({ apiKey: process . env . SUPERTONE_API_KEY });
Voice IDs are not environment variables — they change per use case, so keep them as plain strings in your code (or pass them from your request payload).
Generate speech
import { Supertone } from "@supertone/supertone" ;
import * as fs from "node:fs" ;
const VOICE_ID = "20160a4c5ba38967330c84" ; // replace with your voice ID
const client = new Supertone ({ apiKey: process . env . SUPERTONE_API_KEY });
const response = await client . textToSpeech . createSpeech ({
voiceId: VOICE_ID ,
apiConvertTextToSpeechUsingCharacterRequest: {
text: "Hello from the TypeScript SDK." ,
language: "en" ,
model: "sona_speech_1" ,
outputFormat: "wav" ,
},
});
if ( response . result instanceof Uint8Array ) {
fs . writeFileSync ( "speech.wav" , response . result );
} else if ( response . result && "getReader" in response . result ) {
const reader = ( response . result as ReadableStream < Uint8Array >). getReader ();
const chunks : Uint8Array [] = [];
while ( true ) {
const { done , value } = await reader . read ();
if ( done ) break ;
if ( value ) chunks . push ( value );
}
fs . writeFileSync ( "speech.wav" , Buffer . concat ( chunks ));
}
Every method is async and returns a Promise. There is no sync alternative.
Stream speech
import { Supertone } from "@supertone/supertone" ;
import * as fs from "node:fs" ;
const VOICE_ID = "20160a4c5ba38967330c84" ; // replace with your voice ID
const client = new Supertone ({ apiKey: process . env . SUPERTONE_API_KEY });
const response = await client . textToSpeech . streamSpeech ({
voiceId: VOICE_ID ,
apiConvertTextToSpeechUsingCharacterRequest: {
text: "This response is streamed chunk by chunk." ,
language: "en" ,
model: "sona_speech_1" ,
},
});
if ( response . result && typeof response . result === "object" && "getReader" in response . result ) {
const reader = ( response . result as ReadableStream < Uint8Array >). getReader ();
const chunks : Uint8Array [] = [];
while ( true ) {
const { done , value } = await reader . read ();
if ( done ) break ;
if ( value ) chunks . push ( value );
}
fs . writeFileSync ( "streamed.wav" , Buffer . concat ( chunks ));
}
Streaming is currently supported on sona_speech_1 only.
Long text auto-chunking
createSpeech and streamSpeech both auto-chunk text longer than 300 characters. Pass the text as-is — the SDK splits it, generates each segment, and merges (or streams) the result.
const response = await client . textToSpeech . createSpeech (
{
voiceId: VOICE_ID ,
apiConvertTextToSpeechUsingCharacterRequest: { text: longText , language: "en" },
},
{
maxTextLength: 300 , // optional override (default 300)
},
);
predictDuration does not auto-chunk — its 300-character limit is enforced.
See Long text for details.
Common operations
// List voices with pagination
const list = await client . voices . listVoices ({ pageSize: 20 });
// Search voices
const search = await client . voices . searchVoices ({
language: "ko,en" ,
style: "happy" ,
});
// Get a single voice
const voice = await client . voices . getVoice ({ voiceId: VOICE_ID });
// Predict duration (no credits deducted)
const { duration } = await client . textToSpeech . predictDuration ({
voiceId: VOICE_ID ,
predictTTSDurationRequest: {
text: "How long will this be?" ,
language: "en" ,
},
});
// Get credit balance
const balance = await client . usage . getCreditBalance ();
Type-safe enums (optional)
For type safety, the SDK exposes enum constants in @supertone/supertone/models:
import * as models from "@supertone/supertone/models" ;
models . APIConvertTextToSpeechUsingCharacterRequestLanguage . En ; // "en"
models . APIConvertTextToSpeechUsingCharacterRequestModel . SonaSpeech1 ; // "sona_speech_1"
Plain string literals ("en", "sona_speech_1") work too — use whichever style you prefer.
Error handling
Errors live in @supertone/supertone/models/errors and all extend SupertoneError:
import { Supertone } from "@supertone/supertone" ;
import * as errors from "@supertone/supertone/models/errors" ;
const client = new Supertone ({ apiKey: process . env . SUPERTONE_API_KEY });
try {
const response = await client . textToSpeech . createSpeech ({ /* ... */ });
} catch ( err ) {
if ( err instanceof errors . TooManyRequestsErrorResponse ) {
console . log ( "Rate limited:" , err . message );
} else if ( err instanceof errors . UnauthorizedErrorResponse ) {
console . log ( "Auth failed:" , err . message );
} else if ( err instanceof errors . PaymentRequiredErrorResponse ) {
console . log ( "Out of credits:" , err . message );
} else if ( err instanceof errors . SupertoneError ) {
console . log ( `HTTP ${ err . statusCode } : ${ err . message } ` );
} else {
throw err ;
}
}
Error class HTTP status BadRequestErrorResponse400 UnauthorizedErrorResponse401 PaymentRequiredErrorResponse402 ForbiddenErrorResponse403 NotFoundErrorResponse404 RequestTimeoutErrorResponse408 PayloadTooLargeErrorResponse413 UnsupportedMediaTypeErrorResponse415 TooManyRequestsErrorResponse429 InternalServerErrorResponse500
Network-layer errors (ConnectionError, RequestTimeoutError, RequestAbortedError, etc.) extend HTTPClientError, not SupertoneError.
Configuration
const client = new Supertone ({
apiKey: process . env . SUPERTONE_API_KEY ,
timeoutMs: 30_000 ,
retryConfig: {
strategy: "backoff" ,
backoff: { initialInterval: 500 , maxInterval: 60_000 , exponent: 1.5 , maxElapsedTime: 3_600_000 },
retryConnectionErrors: true ,
},
});
Python SDK The equivalent SDK for Python.
Examples Recipes for common workflows.