API documentation
Generate speech and clone voices from your own app. All endpoints are REST over HTTPS and return JSON.
API access is included in the Studio plan. Create keys in Dashboard → API keys.
Authentication
Send your secret key in the x-api-key header. Keys start with vn_. Keep keys on your server — never put them in browser or mobile code.
x-api-key: vn_your_api_keyRate limits
50 requests per minute per key (sliding window). Over the limit you get 429 RATE_LIMITED with a Retry-After header in seconds.
Credits
Usage is metered in characters: one character of input text = one credit. Cloning is free. Every success response includes a credits object. If a request costs more than your balance it fails with 402 before any audio is generated.
GET/v1/voices
Returns your cloned voices plus library voices you can use.
{
"success": true,
"data": [
{ "voice_id": "v_8hK2…", "name": "Morgan", "gender": "Female", "language": "en", "owner": "you" }
]
}POST/v1/voice-clone
multipart/form-data
| Field | Type | Notes |
|---|---|---|
audio | file · required | WAV or MP3, max 4.4 MB on this hosted site (25 MB on local hosting). Clean 10–30s recording works best. |
name | string · required | 2–80 characters. |
gender | string | Male, Female, Neutral, Unspecified (default). |
language | string | ISO 639-1 code, e.g. en, ur, ar. Default en. |
{
"success": true,
"message": "Your voice has been cloned successfully.",
"data": { "voiceId": "v_8hK2…", "name": "Morgan", "language": "en", "gender": "Female", "createdAt": "2026-10-09T09:20:44.120Z" },
"credits": { "cost": 0, "used": 0, "remaining": 1000000, "total": 1000000 }
}
You may only clone voices you own or have the speaker’s written permission to use.
POST/v1/text-to-speech
application/json
| Field | Type | Notes |
|---|---|---|
text | string · required | Up to 50,000 characters. Long input is generated in parallel and stitched into one file. |
voice_id | string · required | From /v1/voices or /v1/voice-clone. |
speed | number | 0.5 – 2.0, default 1. |
title | string | Optional label shown in your dashboard history. |
{
"success": true,
"message": "Your audio has been generated successfully.",
"data": { "audio_url": "/v1/audio/g_x7…", "id": "g_x7…", "voice_id": "v_8hK2…", "format": "wav", "characters": 44, "speed": 1 },
"credits": { "cost": 44, "used": 44, "remaining": 999956, "total": 1000000 }
}
Use the returned format for the file extension. Library voices return WAV; some cloned voices return MP3. Send your x-api-key header when fetching audio or clone samples; private files require authentication. Append ?dl=1 to force a download. Voice IDs are permanent, opaque values; pass them unchanged.
const audio = await fetch(json.data.audio_url, {
headers: { "x-api-key": process.env.VS_API_KEY }
});
if (!audio.ok) throw new Error("Audio download failed");
await fs.writeFile(`voiceover.${json.data.format}`, Buffer.from(await audio.arrayBuffer()));
A 429 error includes retryAfterSeconds. Wait that long before submitting again. Avoid automatically retrying speech or clone requests after a timeout, as the original request may already have completed.
GET/v1/credits
Returns your current plan and character balance.
Errors
Always branch on success. Failures return {"success": false, "error": {"code", "message", "fields?"}}.
| HTTP | Code | Meaning |
|---|---|---|
| 401 | MISSING_API_KEY | No x-api-key header. |
| 401 | INVALID_KEY_FORMAT | Key does not start with vn_. |
| 401 | INVALID_API_KEY | Key not recognised or deleted. |
| 403 | PLAN_REQUIRED | API needs Studio plan. |
| 429 | RATE_LIMITED | Over 50 req/min — wait Retry-After seconds. |
| 422 | VALIDATION_ERROR | See fields for details. |
| 402 | INSUFFICIENT_CHARACTERS | Not enough balance. |
| 422 | AUDIO_REJECTED | Sample couldn’t be processed — try a cleaner recording. |
| 502/504 | GENERATION_FAILED / GENERATION_TIMEOUT | Retry, or shorten the text. |
| 503 | ENGINE_UNAVAILABLE | Temporary outage — retry shortly. |
| 500 | INTERNAL_ERROR | Unexpected error — retry, then contact support. |