Skip to content

Authentication and API keys ​

Create and manage API keys, set permissions, and issue short-lived WebSocket tickets.

API keys are server credentials ​

Every developer API request uses this header:

http
Authorization: Bearer vlk_<your-secret>

API keys are intended for backend jobs, CLI tools, and private services. Do not expose them in a browser bundle, mobile app, public Git repository, URL, or client-side local storage. If a key is exposed, revoke it immediately and create a replacement.

The backend stores only a hash of the secret. The plaintext secret is returned once, when the key is created.

Permission model ​

Use GET /api/v1/account/api-key-permissions to render the dashboard's key editor. Only entries with implemented: true should be offered for selection:

PermissionLevelsGives access to
text_to_speechnone, read, write, accessTTS generation and/or TTS history
tts_realtimenone, accessRealtime TTS tickets and WebSocket
speech_to_textnone, read, write, accessSTT transcription and/or STT history
stt_realtimenone, accessRealtime STT tickets and WebSocket
audio_isolationnone, read, write, accessVoice Isolator jobs, retained audio, and exports
meetingsnone, read, write, accessMeeting AI uploads, transcripts, notes, and meeting management
llmnone, read, write, accessModel discovery, chat completions, files, and LLM request status
voicesnone, read, write, accessVoice catalog, verified cloning, and owner-only clone management
webhooksnone, accessCreate, read and manage callback subscriptions and deliveries

Meaning of levels:

  • none: no access; omit it from the saved map or send it as none.
  • read: list, inspect, or download existing resources. For Voice Isolator, requesting a new export conversion requires write access.
  • write: create, edit, or delete resources.
  • access: all operations for that permission, including read and write where supported.

Entries with implemented: false are unavailable. Keep them disabled in your UI.

The current legacy scope equivalents are:

ScopeEquivalent permission
tts:readtext_to_speech: read
tts:writetext_to_speech: write
tts:realtimetts_realtime: access
stt:readspeech_to_text: read
stt:writespeech_to_text: write
stt:realtimestt_realtime: access
llm:readllm: read
llm:writellm: write
voices:readvoices: read
voices:writevoices: write
audio_isolation:readaudio_isolation: read
audio_isolation:writeaudio_isolation: write
meetings:readmeetings: read
meetings:writemeetings: write
webhooks:writewebhooks: access, including reads

Use permissions for new integrations. scopes remains available for backwards compatibility, but a request must not contain both.

LLM access ​

For LLM completions, grant {"llm":"access"} in the permission map. Read access lists models and retrieves account-scoped request status. Write access generates completions and uploads/deletes files. Read access also lists and inspects those files. A write-only key cannot read model prices or inspect request usage; grant both for the complete workflow.

Existing unrestricted keys work. Restricted keys need an explicit LLM grant. When editing a key, preserve its other required permissions: permissions replaces the complete map. The compatibility scopes are llm:read and llm:write.

Developer LLM endpoints require a server-side API key and spend credits. Platform JWTs authorize Ask's /api/v1/llm/* and /api/v1/chats/* routes, which remain uncharged; they cannot authorize developer completions.

Voice Cloning access ​

Grant {"voices":"access"} for Voice Cloning: upload a reference, review its transcript, issue and record a live challenge, then use or manage the verified private clone. read permits catalog/session/metadata reads; write permits enrollment, editing and deletion. Separate tts:write access is required to synthesize speech. Active paid plans qualify for enrollment; consent and both content/speaker checks remain mandatory for API keys.

For restricted keys, add write permission and preserve the rest of the map. Unrestricted keys can use all implemented endpoints. See the cloning reference for ownership, rate limits and retries.

Webhook access ​

Grant {"webhooks":"access"} for Webhooks. All subscription and delivery operations, including GET requests, require webhooks:write. Grant the relevant product read permission separately to retrieve a generation or transcription mentioned in an event. The webhook signing secret verifies callbacks and cannot authenticate API requests.

Voice Isolator access ​

For the complete Voice Isolator workflow, grant audio_isolation: access in the permission map. Read access lists jobs, retrieves their status, and downloads available audio or exports. Write access submits files or batches, requests new export conversions, and hides jobs. A write-only key cannot poll results.

Restricted keys need an explicit grant; existing keys do not gain this permission automatically. Unrestricted keys can use all implemented endpoints. Check the permission catalog for support before offering Voice Isolator in a key editor. The developer routes use /v1/voice-isolations; dashboard /api/v1/voice-isolations routes require a user JWT.

Revoking a key blocks new access but does not cancel accepted jobs. Revoke keys referenced by retained jobs instead of permanently deleting them.

Meeting AI access ​

For the complete Meeting AI workflow, grant meetings: access in the permission map. Read access checks capabilities, lists meetings, and retrieves status, transcripts and notes. Write access uploads recordings, renames and deletes meetings, and regenerates failed notes. A write-only key cannot poll results.

Meeting AI is available to personal workspace keys only; team workspace keys return 403 workspace_product_unavailable. Restricted keys need an explicit grant. The developer routes use /v1/meetings; dashboard /api/v1/meetings routes require a user JWT. Revoking a key does not cancel accepted meetings.

List permission and scope catalogs ​

These endpoints require a user access JWT, not a developer API key:

GEThttps://api.voicelab.uz/api/v1/account/api-key-permissions

List the current permission catalog for the API-key editor.

GEThttps://api.voicelab.uz/api/v1/account/api-key-scopes

List legacy API-key scopes for backwards compatibility.

Permission response:

json
{
  "data": {
    "permissions": [
      {
        "id": "text_to_speech",
        "name": "Text to speech",
        "description": "Read TTS history and generate speech from text.",
        "levels": ["none", "read", "write", "access"],
        "implemented": true
      }
    ]
  },
  "request_id": "req_01J..."
}

Scope response:

json
{
  "scopes": [
    {
      "id": "tts:write",
      "name": "TTS write",
      "description": "Create and delete TTS generations."
    }
  ],
  "request_id": "req_01J..."
}

Create a key ​

POSThttps://api.voicelab.uz/api/v1/account/api-keys

Create a scoped developer API key with a user access JWT.

Example using permissions:

json
{
  "name": "Production speech service",
  "permissions": {
    "text_to_speech": "access",
    "speech_to_text": "access",
    "tts_realtime": "access",
    "voices": "read"
  },
  "expires_at": null,
  "restrict_key": true,
  "credit_limit": null,
  "allowed_ips": ["203.0.113.10"],
  "auto_disable_if_leaked": true
}

Fields:

FieldRequiredRules
nameyes1–80 characters; control characters are rejected
permissionsno*Map of supported permission IDs to levels; {} clears all access
scopesno*Legacy array; use this only when permissions is absent
expires_atnoFuture RFC3339 timestamp or null for no expiry
restrict_keynoDefaults to true
credit_limitnoNon-negative integer or null
allowed_ipsnoUp to 100 IPv4, IPv6, or CIDR entries
auto_disable_if_leakednoDefaults to true

* Keys without product permissions cannot call product endpoints.

Legacy request example:

json
{
  "name": "Legacy TTS key",
  "scopes": ["tts:read", "tts:write", "voices:read"]
}

Do not send both permissions and scopes.

201 Created:

json
{
  "data": {
    "key": {
      "id": "key_01J...",
      "name": "Production speech service",
      "masked_key": "vlk_••••••••9x2a",
      "prefix": "vlk_",
      "permissions": {
        "text_to_speech": "access",
        "speech_to_text": "access",
        "tts_realtime": "access",
        "voices": "read"
      },
      "scopes": ["tts:read", "tts:write", "tts:realtime", "stt:read", "stt:write", "voices:read"],
      "created_at": "2026-08-16T12:00:00Z",
      "last_used_at": null,
      "expires_at": null,
      "enabled": true,
      "revoked_at": null,
      "restrict_key": true,
      "credit_limit": null,
      "allowed_ips": ["203.0.113.10"],
      "auto_disable_if_leaked": true,
      "leaked_at": null
    },
    "secret": "vlk_<long-secret-returned-once>"
  },
  "request_id": "req_01J..."
}

Show the secret once and ask the user to copy it. It is never returned by list, update, or any product endpoint.

List keys ​

GEThttps://api.voicelab.uz/api/v1/account/api-keys?limit=50&cursor=<opaque>

List API keys with cursor pagination.

limit defaults to 50 and must be 1–100. The response is:

json
{
  "data": {
    "keys": [
      {
        "id": "key_01J...",
        "name": "Production speech service",
        "masked_key": "vlk_••••••••9x2a",
        "enabled": true,
        "created_at": "2026-08-16T12:00:00Z",
        "expires_at": null,
        "revoked_at": null,
        "permissions": {"text_to_speech": "access"}
      }
    ],
    "next_cursor": null
  },
  "request_id": "req_01J..."
}

Edit a key ​

PATCHhttps://api.voicelab.uz/api/v1/account/api-keys/{key_id}

Update an API key's name, permissions, restrictions, or lifecycle settings.

The body is a partial update:

json
{
  "name": "Production speech service v2",
  "enabled": true,
  "expires_at": "2027-08-16T00:00:00Z",
  "permissions": {
    "text_to_speech": "access",
    "tts_realtime": "access",
    "voices": "read"
  }
}
  • Omitted fields stay unchanged.
  • expires_at: null removes expiry. Omit it to keep the current expiry.
  • permissions replaces the complete permission map. Omitted permissions are removed; {} removes all permissions.
  • Use either permissions or legacy scopes, never both.
  • The secret is never returned by PATCH.
  • The update is atomic.

200 OK returns { "data": { "key": { ... } }, "request_id": "..." }.

Revoke versus delete ​

Revoke a key to stop access while keeping its audit history:

POSThttps://api.voicelab.uz/api/v1/account/api-keys/{key_id}/revoke

Immediately stop an API key from authenticating.

204 No Content means the key stops authenticating immediately. Its metadata and audit history remain available.

Delete is permanent:

DELETEhttps://api.voicelab.uz/api/v1/account/api-keys/{key_id}

Permanently delete an API-key record.

204 No Content confirms deletion. If existing work still references the key, the API returns 409 api_key_in_use; revoke it instead.

Key-management errors ​

StatusCodeMeaning
400invalid_json, validation_error, invalid_paginationRequest or fields are invalid
401session_expiredUser JWT is missing, invalid, or expired
403origin_forbiddenBrowser origin is not allowed for this dashboard action
404not_foundKey is not owned by this account
409api_key_in_usePermanent deletion is blocked by existing work
500internal_errorUnexpected server error
503auth_unavailable, service_unavailableRequired service is unavailable