Theme
VoiceLab API
Generate text and speech, transcribe or clean up audio, clone your voice, and stream realtime audio.
Keep your API key on your server. Product endpoints use API keys; account management uses a signed-in user's JWT.
Latest STT update
October 9, 2026: STT now accepts 33 languages, including Chinese and Azerbaijani, plus language=auto for automatic detection in uploaded recordings and realtime requests. See the language codes, timing behavior, and availability notes. Existing API routes and request formats are unchanged.
Base URL
text
https://api.voicelab.uzThe public developer API uses the /v1 prefix. For example:
text
POST https://api.voicelab.uz/v1/ttsChoose the right credential
| Credential | Used for | Example |
|---|---|---|
| User access JWT | VoiceLab website and API-key management | Authorization: Bearer eyJ... |
| Developer API key | Your application calling LLM, TTS, STT, Voice Isolator, Meeting AI, voices, and realtime ticket endpoints | Authorization: Bearer vlk_... |
| Realtime ticket | One short-lived WebSocket connection | ?ticket=eyJ... |
Do not send a user JWT to /v1/tts, /v1/stt, or /v1/voices. Do not send a long-lived API key in a WebSocket URL. The only value allowed in that URL is a short-lived ticket returned by POST /v1/ticket.
Voice Isolator developer requests use an API key at /v1/voice-isolations. The dashboard routes at /api/v1/voice-isolations require a user JWT.
Meeting AI developer requests use a personal workspace API key at /v1/meetings. The dashboard routes at /api/v1/meetings require a user JWT.
Endpoints
Create and manage keys with the signed-in dashboard:
| Method | Endpoint | Credential |
|---|---|---|
GET | /api/v1/account/api-key-permissions | User JWT |
GET | /api/v1/account/api-key-scopes | User JWT |
POST | /api/v1/account/api-keys | User JWT |
GET | /api/v1/account/api-keys | User JWT |
PATCH | /api/v1/account/api-keys/{key_id} | User JWT |
POST | /api/v1/account/api-keys/{key_id}/revoke | User JWT |
DELETE | /api/v1/account/api-keys/{key_id} | User JWT |
Use the generated key for application services:
| Feature | Endpoints | Permission |
|---|---|---|
| LLM models | GET /v1/models | llm:read |
| Chat completion | POST /v1/chat/completions | llm:write |
| LLM request status | GET /v1/llm/requests/{id} | llm:read |
| LLM files | POST, GET /v1/files, GET, DELETE /v1/files/{file_id} | llm:read for reads, llm:write for upload/delete |
| TTS capabilities | GET /v1/tts/languages | TTS read |
| Voices | GET /v1/voices?language={code} | Voices read |
| Clone discovery/state | GET /v1/voice-enrollments/capabilities, GET /v1/voice-enrollments/{id} | voices:read |
| Verified voice enrollment | POST /v1/voice-enrollments, then /{id}/transcript, /{id}/challenge, /{id}/verify | voices:write |
| Clone metadata | GET /v1/voices/{id} | voices:read |
| Edit/delete own clone | PATCH /v1/voices/{id}, DELETE /v1/voices/{id} | voices:write |
| TTS generation | POST /v1/tts | TTS write |
| Background TTS | POST /v1/tts/async | TTS write; TTS read for polling |
| TTS history | GET /v1/tts/generations, GET /v1/tts/generations/{id} | TTS read |
| Delete TTS audio | DELETE /v1/tts/generations/{id} | TTS write |
| STT transcription | POST /v1/stt | STT write |
| STT credit preflight | GET /v1/stt/preflight | STT write |
| STT history and files | GET /v1/stt/transcriptions... | STT read |
| Edit or delete STT | PATCH, PUT, DELETE /v1/stt/transcriptions/{id} | STT write |
| Voice isolation | POST /v1/voice-isolations, POST /v1/voice-isolations/batch | audio_isolation:write |
| Isolation history and results | GET /v1/voice-isolations, GET /v1/voice-isolations/{id} | audio_isolation:read |
| Hide isolation | DELETE /v1/voice-isolations/{id} | audio_isolation:write |
| Create isolation export | POST /v1/voice-isolations/{id}/exports | audio_isolation:write |
| Get isolation export | GET /v1/voice-isolations/{id}/exports/{format} | audio_isolation:read |
| Meeting AI capabilities | GET /v1/meetings/capabilities | meetings:read |
| Create meeting | POST /v1/meetings | meetings:write |
| Meeting history and results | GET /v1/meetings, GET /v1/meetings/{id} | meetings:read |
| Rename or delete meeting | PATCH, DELETE /v1/meetings/{id} | meetings:write |
| Regenerate meeting notes | POST /v1/meetings/{id}/notes/generations | meetings:write |
| Realtime TTS | POST /v1/ticket, then GET /v1/tts/stream | TTS realtime |
| Realtime STT | POST /v1/ticket, then GET /v1/stt/stream | STT realtime |
| Webhooks and deliveries | /v1/webhooks...; see complete reference | webhooks:write, including reads |
Grant Voice Isolator → Access for the complete upload, polling, and export workflow. This enables both isolation scopes. Existing restricted keys need this permission added explicitly. See Voice Isolator.
Grant Meeting AI → Access to upload recordings, poll results, and manage meetings. This enables both meeting scopes. Only personal workspace keys can use Meeting AI. See Meeting AI.
Grant llm: access for model discovery, completions, and request status. Developer LLM requests use API keys and token-based credits. Ask's /api/v1/llm/* and /api/v1/chats/* routes remain JWT-only and uncharged. See LLM API.
Grant Voices → Access for the verified Voice Cloning workflow and owner-only editing/deletion. All active paid plans qualify; consent, a fresh live recording and both verification checks are required.
Analytics and request logs are dashboard views. They use a user JWT and show only traffic authenticated with developer API keys; website JWT traffic is not included. See Analytics and logs.
Quick start
1. Create an API key
Use a user access JWT from the VoiceLab dashboard to create a key. The secret is returned only in this response.
bash
curl -X POST 'https://api.voicelab.uz/api/v1/account/api-keys' \
-H 'Authorization: Bearer USER_ACCESS_JWT' \
-H 'Content-Type: application/json' \
-d '{
"name": "My production integration",
"permissions": {
"text_to_speech": "access",
"speech_to_text": "access",
"voices": "read"
},
"expires_at": null,
"restrict_key": true,
"auto_disable_if_leaked": true
}'Save data.secret immediately. It cannot be recovered later.
2. Store the key on your server
bash
export VOICELAB_API_KEY='vlk_replace_with_the_secret_from_creation'For production, use your deployment secret manager instead of a shell file.
3. Generate speech
bash
tts_http_status=$(curl -fS -w '%{http_code}' 'https://api.voicelab.uz/v1/tts' \
-H "Authorization: Bearer $VOICELAB_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: hello-world-001' \
-d '{
"text": "Hello from VoiceLab.",
"language": "en",
"voice_id": "voice_01J9NEUTRAL0000000000000001",
"speed": 1
}' \
-o tts-response)
case "$tts_http_status" in
200) mv tts-response hello.wav ;;
202) cat tts-response ;; # Poll the returned status_url before downloading audio
*) cat tts-response >&2; exit 1 ;;
esacOutput is mono 24 kHz WAV. Fetch available models and languages from /v1/tts/languages. If generation is pending, the response is 202 JSON instead of audio. See TTS polling.
4. Transcribe audio
bash
curl -fS 'https://api.voicelab.uz/v1/stt' \
-H "Authorization: Bearer $VOICELAB_API_KEY" \
-H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
-F 'audio=@meeting.wav;type=audio/wav' \
-F 'language=en' \
-F 'include_speakers=false'See Speech to Text for upload limits and polling.
Common response rules
- JSON responses use
Content-Type: application/json. - Resource timestamps are RFC 3339 UTC strings, for example
2026-08-16T12:30:00Z. LLM completioncreatedand filecreated_at/expires_atuse Unix seconds; modelcreatedis0. - IDs, cursors, tickets, and URLs are opaque. Do not parse or construct them.
- Standard resource responses include
request_id. LLM success bodies use their own shapes; completion headers includeX-LLM-Request-ID. LLM streaming uses SSE. See LLM response formats. - TTS returns WAV audio or pending-job JSON. STT exports return files. Voice Isolator returns JSON with signed download URLs.
- Private audio URLs are short-lived signed URLs. Do not store them as permanent links.
Error response
Standard JSON errors use this shape:
json
{
"message": "This API key is not allowed to perform this operation.",
"error": {
"code": "insufficient_scope"
},
"request_id": "req_01J..."
}LLM handler errors put the message in error.message and include error.type. Shared authentication errors can still use the standard shape shown above. Handle both envelopes when integrating LLM endpoints.
Some validation errors also contain error.fields:
json
{
"message": "Check the highlighted fields.",
"error": {
"code": "validation_error",
"fields": {
"language": "Choose a supported language."
}
},
"request_id": "req_01J..."
}Always log request_id in your application. Never log an API key, realtime ticket, audio bytes, or signed audio URL.