Configure individual API requests with timeouts, retries, abort signals, and custom headers. Request options override client-level defaults for specific requests.
import { RequestOptions } from "@elevenlabs/elevenlabs-js";
// Request options can be passed as the last argument to any API methodAll API methods accept optional request-specific configuration that overrides client defaults.
interface RequestOptions {
/** Override default timeout in seconds */
timeoutInSeconds?: number;
/** Override default max retries */
maxRetries?: number;
/** Abort signal for cancellation */
abortSignal?: AbortSignal;
/** Override API key for this request */
apiKey?: string;
/** Additional query parameters */
queryParams?: Record<string, unknown>;
/** Additional headers for this request. Supplier<T> allows static values, promises, or functions */
headers?: Record<string, string | Supplier<string>>;
}
/**
* Supplier type for values that can be static, promises, or functions
*/
type Supplier<T> = T | Promise<T> | (() => T | Promise<T>);import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
const client = new ElevenLabsClient({
apiKey: "your-api-key",
timeoutInSeconds: 60, // Default timeout
});
// Use longer timeout for specific request
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Long text that takes time to generate..." },
{ timeoutInSeconds: 300 } // 5 minutes for this request
);// Disable retries for specific request
const result = await client.voices.getAll(
{},
{ maxRetries: 0 } // No retries
);
// Increase retries for unreliable operation
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{ maxRetries: 5 } // More attempts
);// Use AbortController to cancel requests
const controller = new AbortController();
// Start long-running request
const audioPromise = client.textToSpeech.convert(
"voice-id",
{ text: "Very long text..." },
{ abortSignal: controller.signal }
);
// Cancel after 5 seconds
setTimeout(() => {
controller.abort();
}, 5000);
try {
const audio = await audioPromise;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
}
}// Use different API key for specific request
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{ apiKey: "different-api-key" }
);// Add custom query parameters
const voices = await client.voices.getAll(
{},
{
queryParams: {
custom_param: "value",
debug: true,
}
}
);// Static headers
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{
headers: {
"X-Custom-Header": "value",
"X-Request-ID": "12345",
}
}
);
// Dynamic headers using functions
const audio2 = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{
headers: {
"X-Timestamp": () => Date.now().toString(),
"X-Random": () => Math.random().toString(),
}
}
);
// Async headers using promises
const audio3 = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{
headers: {
"X-Token": async () => {
const token = await fetchToken();
return token;
},
}
}
);// Combine multiple request options
const controller = new AbortController();
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello, world!" },
{
timeoutInSeconds: 120,
maxRetries: 3,
abortSignal: controller.signal,
headers: {
"X-Request-ID": "unique-id",
"X-Priority": "high",
},
queryParams: {
experimental: true,
}
}
);// Set timeout for streaming operations
const audioStream = await client.textToSpeech.stream(
"voice-id",
{
text: "Streaming audio...",
optimize_streaming_latency: 4,
},
{
timeoutInSeconds: 180, // 3 minutes for stream
}
);
for await (const chunk of audioStream) {
// Process chunks
}// Apply different options based on conditions
async function generateAudio(
text: string,
isUrgent: boolean
): Promise<ReadableStream<Uint8Array>> {
const options: RequestOptions = isUrgent
? {
timeoutInSeconds: 30,
maxRetries: 5,
headers: { "X-Priority": "high" },
}
: {
timeoutInSeconds: 120,
maxRetries: 2,
};
return await client.textToSpeech.convert(
"voice-id",
{ text },
options
);
}// Add debugging information to requests
const requestId = crypto.randomUUID();
try {
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{
headers: {
"X-Request-ID": requestId,
"X-Debug-Mode": "true",
},
queryParams: {
debug: true,
}
}
);
console.log(`Request ${requestId} succeeded`);
} catch (error) {
console.error(`Request ${requestId} failed:`, error);
}// Implement custom retry logic with request options
async function generateWithRetry(
voiceId: string,
text: string,
maxAttempts: number = 3
): Promise<ReadableStream<Uint8Array>> {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await client.textToSpeech.convert(
voiceId,
{ text },
{
maxRetries: 0, // Disable SDK retries, we handle it
timeoutInSeconds: 60,
headers: {
"X-Attempt": attempt.toString(),
}
}
);
} catch (error) {
if (attempt === maxAttempts) throw error;
// Wait before retry (exponential backoff)
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error("All attempts failed");
}// Set custom user agent
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{
headers: {
"User-Agent": "MyApp/1.0.0 (Custom Client)",
}
}
);// Add tracing headers for distributed systems
const traceId = generateTraceId();
const spanId = generateSpanId();
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Hello" },
{
headers: {
"X-Trace-ID": traceId,
"X-Span-ID": spanId,
"X-Parent-Span-ID": parentSpanId,
}
}
);// Short operations (< 10s): Use default or shorter timeout
const voices = await client.voices.getAll(
{},
{ timeoutInSeconds: 10 }
);
// Medium operations (10-60s): Standard timeout
const audio = await client.textToSpeech.convert(
"voice-id",
{ text: "Medium length text" },
{ timeoutInSeconds: 60 }
);
// Long operations (> 60s): Extended timeout
const dubbing = await client.dubbing.create(
{ /* large video */ },
{ timeoutInSeconds: 600 } // 10 minutes
);// Idempotent operations: Safe to retry
const voices = await client.voices.getAll(
{},
{ maxRetries: 3 }
);
// Non-idempotent operations: Be cautious with retries
const voice = await client.voices.ivc.create(
{ name: "New Voice", files: samples },
{ maxRetries: 1 } // Fewer retries to avoid duplicates
);
// Critical operations: Disable retries for predictable behavior
const deleted = await client.voices.delete(
"voice-id",
{ maxRetries: 0 }
);// Create reusable abort controller
const controller = new AbortController();
// Use same signal for multiple requests
const requests = [
client.textToSpeech.convert("voice-1", { text: "Hello" },
{ abortSignal: controller.signal }),
client.textToSpeech.convert("voice-2", { text: "World" },
{ abortSignal: controller.signal }),
];
// Cancel all requests at once
setTimeout(() => controller.abort(), 5000);
try {
await Promise.all(requests);
} catch (error) {
// Handle cancellation
}