TypeScript REST client for the ResponsiveVoice Text-to-Speech API.
Documentation | Browser Support
# npm
npm install @responsivevoice/api-client
# pnpm
pnpm add @responsivevoice/api-client
# yarn
yarn add @responsivevoice/api-clientYou need both an API key and an API secret to authenticate your requests — neither works alone.
- Register for a free ResponsiveVoice account.
- A default website is created for you automatically. Its identifier is your API key — copy it from the dashboard.
- Create your API secret manually in the dashboard section "Server-to-server API secrets" (it is not auto-generated).
- The secret is shown once: click to copy it immediately and paste it straight into your code (next to the API key from step 2). It can't be retrieved later — if you lose it, create a new one.
Keep your API secret server-side — don't ship it in browser code.
import { ResponsiveVoiceAPIClient } from '@responsivevoice/api-client';
// Authenticate with BOTH your API key and API secret (see above).
const client = new ResponsiveVoiceAPIClient({
apiKey: 'your-api-key',
apiSecret: 'your-api-secret',
});
// Synthesize speech: pass text and a ResponsiveVoice voice name.
// The server resolves the right voice for you.
const audio = await client.synthesize({
text: 'Hello, world!',
voice: 'UK English Female',
format: 'mp3',
});
// The result gives you the audio in a few forms:
audio.blob; // the raw audio Blob
audio.url; // an object URL you can play
audio.format; // 'mp3'
audio.duration; // length in seconds (when known)
// Play it in the browser
const audioElement = new Audio(audio.url);
audioElement.play();
// Free the object URL when you're done with it
URL.revokeObjectURL(audio.url);new ResponsiveVoiceAPIClient(config: ResponsiveVoiceAPIClientConfig)| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
required | Your registered website/origin identifier |
apiSecret |
string |
required | The credential that authorizes requests |
baseUrl |
string |
https://texttospeech.responsivevoice.org/v2 |
API base URL |
timeout |
number |
30000 |
Request timeout in milliseconds |
retryAttempts |
number |
3 |
Number of retry attempts for transient errors |
retryDelay |
number |
1000 |
Base delay between retries in milliseconds |
fetch |
typeof fetch |
globalThis.fetch |
Custom fetch implementation |
Synthesize text to speech audio.
const audio = await client.synthesize({
text: 'Hello, world!',
voice: 'UK English Female', // ResponsiveVoice name (resolved server-side)
pitch: 0.5, // 0-1, optional
rate: 0.5, // 0-1, optional
volume: 1.0, // 0-1, optional
format: 'mp3', // 'mp3' | 'ogg' | 'wav', optional
gender: 'female', // 'male' | 'female', optional
});
console.log(audio.blob); // Blob
console.log(audio.url); // string (blob URL)
console.log(audio.format); // 'mp3' | 'ogg' | 'wav'
console.log(audio.duration); // number | undefined (seconds)Get all available voices, optionally filtered.
// getVoices() returns { voices, systemVoices } — destructure what you need.
// Get all voices
const { voices } = await client.getVoices();
// Filter by language
const { voices: britishVoices } = await client.getVoices({ lang: 'en-GB' });
// Filter by gender
const { voices: femaleVoices } = await client.getVoices({ gender: 'female' });
// Filter by both
const { voices: britishFemaleVoices } = await client.getVoices({
lang: 'en-GB',
gender: 'female',
});Get a specific voice by name.
const voice = await client.getVoice('UK English Female');
console.log(voice.name); // 'UK English Female'
console.log(voice.lang); // 'en-GB'
console.log(voice.service); // 'g1'Get all voices for a specific language.
const germanVoices = await client.getVoicesByLanguage('de-DE');
const frenchVoices = await client.getVoicesByLanguage('fr');All methods accept an optional RequestOptions object:
interface RequestOptions {
timeout?: number; // Custom timeout for this request
signal?: AbortSignal; // Abort signal for cancellation
skipRetry?: boolean; // Skip retry logic for this request
}Example with abort:
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const audio = await client.synthesize(
{ text: 'Long text...', lang: 'en-US' },
{ signal: controller.signal },
);
} catch (error) {
if (error.name === 'TimeoutError') {
console.log('Request was cancelled');
}
}The client throws specific error types for different failure scenarios:
import {
ResponsiveVoiceError, // Base error class
ApiError, // API returned an error response
AuthError, // Authentication failed (401/403)
NotFoundError, // Resource not found (404)
RateLimitError, // Rate limited (429)
ValidationError, // Request validation failed (400)
NetworkError, // Network connectivity issues
TimeoutError, // Request timed out
RetryExhaustedError, // All retry attempts failed
} from '@responsivevoice/api-client';
try {
const audio = await client.synthesize({ text: '', lang: 'en-US' });
} catch (error) {
if (error instanceof ValidationError) {
console.error('Validation failed:', error.errors);
} else if (error instanceof AuthError) {
console.error('Authentication failed:', error.message);
} else if (error instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
} else if (error instanceof TimeoutError) {
console.error(`Request timed out after ${error.timeout}ms`);
} else if (error instanceof NetworkError) {
console.error('Network error:', error.message);
}
}The client automatically retries requests that fail due to:
- Server errors (5xx status codes)
- Rate limiting (429) - uses
Retry-Afterheader if provided - Network errors
Client errors (4xx except 429) are NOT retried.
Retry uses exponential backoff with jitter:
- Base delay: 1000ms
- Multiplier: 2x per attempt
- Max delay: 30000ms
You can customize retry behavior:
const client = new ResponsiveVoiceAPIClient({
apiKey: 'your-key',
apiSecret: 'your-secret',
retryAttempts: 5, // More attempts
retryDelay: 500, // Faster initial retry
});Or skip retries for a specific request:
const audio = await client.synthesize(
{ text: 'Hello', lang: 'en-US' },
{ skipRetry: true },
);This package supports all modern browsers. For detailed compatibility information, see the Browser Support documentation.
Minimum browser versions:
- Chrome 66+
- Firefox 57+
- Safari 12+
- Edge 17+
The package requires Node.js 16+ and works in both Node.js and browser environments.
Node.js 18+ — all features work out of the box (native fetch, Blob, AbortController).
Node.js 16–17 — pass a fetch implementation via config:
import fetch from 'node-fetch';
const client = new ResponsiveVoiceAPIClient({
apiKey: 'your-key',
apiSecret: 'your-secret',
fetch,
});WebSocket streaming on Node.js < 22 — the global WebSocket was added in Node.js 22. On older versions, pass a WebSocket implementation:
import WebSocket from 'ws';
import { WebSocketConnection } from '@responsivevoice/api-client';
const ws = new WebSocketConnection({
baseUrl: 'https://texttospeech.responsivevoice.org',
apiKey: 'your-key',
WebSocket,
});MIT
Other language SDKs: Python · Go · PHP · Java
AI coding agents: install the ResponsiveVoice skill — npx skills add responsivevoice/skills