GET /api/tts/turbo/channel —TURBO_CHANNEL_NOT_FOUND (the two cases are not distinguished).status, no data field./socket/tts/turbo/channel/{turboChannelId} (app.js:485 allowlist)wsUrl from the response directly; it already includes ?auth={32-character static token}auth query is looked up in Redis auth:user:{token} to obtain userId;HTTP/1.1 401 Unauthorized (not a JSON error body)TURBO_CHANNEL_NOT_FOUND;TURBO_RESOURCE_EXHAUSTED (both are sent as an error frame, then the socket is closed immediately)binary=1 (or format=binary) enables binary audio mode: audio is delivered as raw PCM16LE binary frames,hex_json mode.| type | Description |
|---|---|
synthesis_request | Submit one utterance of text to synthesize. Note the type is named synthesis_request, not speak |
cancel | Interrupt the current utterance (barge-in). Instruct channels only; a regular channel returns VALIDATION_BAD_PARAMS |
ping | Heartbeat; the server replies with pong |
close_channel | Actively close the channel and release the concurrency slot. The type is named close_channel, not close |
data field of synthesis_request differs by channel type:{ text, promptId?, language?, preset?, seed?, speechRate?, emo_switch?, vivid?,
gamble?, post_processing?, infinite_mode?, break_clone?, break_time?, break_float_time?, volume?,
temperature?, top_k?, top_p?, presence_penalty?, frequency_penalty?, repetition_penalty?, min_p? }/api/tts/simple-generate parameters{ text, language? } only. text may contain {{...}} emotion-control markers;| type | Description |
|---|---|
connected | Client connected successfully. data contains the audio encoding description; instruct channels additionally include features |
audio_chunk | One audio frame. data.hex is hex-encoded PCM16LE @24kHz mono; an empty frame = utterance boundary |
audio_generated | One utterance finished. data.audioUrl is the WAV URL; when save_audio:false it is null and saved:false is present |
audio_generate_failed | This utterance failed (not billed); the channel stays alive and the client may resend |
cancelled | Interrupt took effect (instruct channels only) |
pong | Heartbeat response |
error | Request-level error; the channel is not closed |
close | Server is closing the channel (upstream disconnect, graceful process exit, etc.); the socket closes afterwards |
buildSocketErrorBody() (modules/errorCodes.js:379), shaped as:requestId — requestId is injected only by the HTTP response interceptor in app.js; WS does not go through that path.audio_generate_failed / audio_generated (when upload fails) / close frames use the same data shape.VALIDATION_MISSING_FIELD (missing text), VALIDATION_TOO_LONG (utterance too long),RATE_LIMIT_CONCURRENT (pending-utterance cap exceeded), RESOURCE_NOT_FOUND (promptId does not exist),VALIDATION_INVALID_VALUE (illegal emo_switch format), VALIDATION_BAD_PARAMS (payload is not JSON, or cancel sent on a regular channel),SAFETY_CHECK_FAILED / CONTENT_MODERATION_BLOCKED (text moderation), BILLING_INSUFFICIENT_CREDIT (insufficient balance),TTS_GENERATE_FAILED (synthesis failed), UPLOAD_FAILED (audio was delivered but WAV upload failed),SYSTEM_INTERNAL_ERROR / SYSTEM_SHUTTING_DOWN (sent with a close frame).INSTRUCT_TTS_MAX_TEXT_CHARS /INSTRUCT_WS_MAX_PENDING_SPEAKS, routes/generate/turbo.js:64-65):TURBO_INSTRUCT_MAX_TEXT_CHARS) — exceeding returns VALIDATION_TOO_LONGTURBO_INSTRUCT_MAX_PENDING_SPEAKS) — exceeding returns RATE_LIMIT_CONCURRENTturboConcurrent: a value < 1 (including unset) means no Turbo permission,TURBO_CONCURRENCY_LIMIT immediately; the same code is returned when all slots are occupied.cancelAfter in the response), otherwise the channel is reclaimed1013 (slow-consumer protection){ status, code, message, requestId? }. code is always the parent code — sub codes only change message and never appear in the body. requestId is present only on reportable-tier errors, so use the X-Vocu-App-Request-Id response header when troubleshooting (it is written unconditionally on every response). See the "Errors" document for the full code reference.