API GuidesSocket.IO Event Reference

Text-to-Speech

Stream PCM16 24 kHz audio over socket.io.

Text-to-Speech (TTS) over Socket.IO.

This API accepts a JSON tts request and streams binary audio chunks via tts_audio.

Quickstart

  1. Connect with the API_URL and API_KEY provisioned for the environment; API_PATH is optional and defaults to /socket.io.
  2. Request tts_voice_list; an empty array is a valid result and must not be replaced with a guessed ID.
  3. Emit tts with a fresh UUID, text containing at least one Unicode letter or number after trimming, and explicit model: "nebula".
  4. Choose either one returned voice_id or one voice_references item; do not send both.
  5. Listen for tts_audio, append bytes 17..end from every matching frame, including the final frame, and finish when byte 16 bit 0 is set.

Supported Features

  • Streaming synthesis: ttstts_audio (binary chunks)
  • Voice profile discovery: tts_voice_listtts_voice_list_result (seven multilingual profiles)
  • Voice adaptation: voice_references (base64 audio + transcript)

Input Validation

After trimming, top-level request text must contain at least one Unicode letter or number. Whitespace-only input emits non-retryable VALIDATION_REQUIRED_FIELD; punctuation-only input emits non-retryable VALIDATION_INVALID_PARAM. The service counts Unicode code points, not UTF-8 bytes or displayed grapheme clusters. Leading and trailing whitespace is preserved and counts toward the limit.

Inclusive defaults are 500 code points for free accounts and 1,000 for standard and enterprise accounts. Missing or unknown tiers use the free limit. Deployments can independently override the limits with TTS_MAX_INPUT_CHARACTERS_FREE, TTS_MAX_INPUT_CHARACTERS_STANDARD, and TTS_MAX_INPUT_CHARACTERS_ENTERPRISE; consequently the schema does not declare a fixed maxLength.

Text over the effective limit emits a non-retryable CHARACTER_COUNT_EXCEEDED error carrying data with bound tts_input_characters. Validation happens before synthesis and before the per-key rate-limit bucket is charged.

text is plain UTF-8 text, not SSML. Markup is neither parsed nor validated: angle brackets carry no meaning, count toward the character limit like any other characters, and a tag's name may be spoken.

Content policy

When content-policy enforcement is enabled, rejected text emits non-retryable TTS_INPUT_NOT_ALLOWED; change the text before trying again. If the content-moderation authority cannot make a decision, synthesis fails closed with retryable TTS_MODERATION_UNAVAILABLE. These outcomes are kept distinct so an infrastructure failure is never reported as prohibited content. Both are emitted before synthesis begins.

Voice-reference limits

voice_references accepts exactly one entry and every bound on it is checked before the model lookup, the concurrency lease and the rate-limit charge, so a rejected request consumes no quota and no slot:

  • more than one entry emits non-retryable VOICE_REFERENCE_COUNT_EXCEEDED (bound tts_voice_reference_count);
  • an explicit empty array emits non-retryable VALIDATION_INVALID_PARAM - omit the field, or send null, to use voice_id or the default voice;
  • supplying voice_id together with voice_references emits non-retryable VALIDATION_INVALID_PARAM;
  • a reference transcript over its own limit (default 500 code points, independent of the text budget) emits CHARACTER_COUNT_EXCEEDED with bound tts_voice_reference_text_characters;
  • decoded reference audio over the byte ceiling (default 2 MiB) emits PAYLOAD_TOO_LARGE with bound tts_voice_reference_bytes, checked from the base64 length before the payload is decoded;
  • decoded reference audio longer than the duration ceiling (default 15 seconds, matching the deployed model's own reference limit) emits AUDIO_DURATION_EXCEEDED with bound tts_voice_reference_duration;
  • base64 that is not strictly canonical, or audio that is not mono PCM16 RIFF/WAVE, emits VALIDATION_INVALID_FORMAT.

Deployments may lower the reference ceilings with TTS_MAX_VOICE_REFERENCE_DECODED_BYTES, TTS_MAX_VOICE_REFERENCE_DURATION_SEC and TTS_MAX_VOICE_REFERENCE_TEXT_CHARACTERS but can never raise them above the published defaults.

Lifecycle and cancellation

The Socket.IO connection owns its active synthesis RPCs; clients do not send an owner field. Disconnecting cancels only that connection's requests and suppresses later audio/error emits without closing inference connections shared with other requests. Synthesis has a non-resetting 25-second overall deadline and a 60-second inactivity watchdog. If the overall deadline wins before the final frame, the server emits retryable TTS_DEADLINE_EXCEEDED; audio already sent remains partial and must be discarded or handled as incomplete.

TTS Audio Output Format

Audio bytes in tts_audio (bytes 17..end) are always:

  • PCM16 little endian
  • 24 kHz
  • mono
  • raw waveform (no WAV header)

Voice Selection

voice_id (if used) is a UUID returned by tts_voice_list_result. If neither voice selector is sent, selection is deployment/model-defined and no voice is guaranteed. Released SDK 0.18.0 applies stricter client-side validation and requires exactly one selector.

The voice list contains only the seven configured multilingual profiles. Every item carries profile metadata with one speaker context and an open-ended list of supported language tags. Physical variant IDs are internal and are rejected when supplied as voice_id.

For the current Arabic/English profiles, the Arabic variant is selected when text contains any Unicode Arabic-script letter. Otherwise the English variant is selected. Numbers, punctuation, emoji, whitespace, and letters from non-Arabic scripts do not select Arabic.

A supplied voice_id is resolved before any quota deduction, rate-limit charge or inference, and its failures are typed (SAU-2258): a voice_id that is not a valid UUID emits non-retryable VALIDATION_INVALID_UUID; a well-formed voice_id that does not identify an available voice emits non-retryable TTS_VOICE_NOT_FOUND; a resolved voice whose stored data is incomplete or corrupt emits non-retryable TTS_VOICE_RESOLUTION_FAILED; and a positively classified transient database/storage outage during resolution emits retryable SERVER_DEPENDENCY_FAILURE. Because resolution precedes any charge, retrying the retryable case is safe.

Connection

Host: wss://api.voice.humain.com

Use the API_URL and API_KEY provisioned for the target environment. API_PATH is optional and defaults to /socket.io, the single path that serves every subsystem; set it only to override for a self-hosted or proxied deployment. This is Socket.IO over WebSocket, not raw WebSocket. Transport: WebSocket only — set transports: ["websocket"]. Polling is not supported.

Example (JavaScript):

const socket = io(process.env.API_URL, {
  path: process.env.API_PATH ?? "/socket.io",
  transports: ["websocket"],
  extraHeaders: { "x-api-key": process.env.API_KEY, "Origin": process.env.API_URL }
});

Example (Python — python-socketio):

async def main() -> None:
    await sio.connect(
        os.environ["API_URL"],
        headers={"x-api-key": os.environ["API_KEY"], "Origin": os.environ["API_URL"]},
        socketio_path=os.environ.get("API_PATH", "/socket.io"),
        transports=["websocket"],
    )

asyncio.run(main())

Authentication: x-api-key (header httpApiKey).

Events

EventDirectionDescription
ttsClient → ServerClient sends JSON TTS request.
tts_audioServer → ClientServer streams TTS audio as binary chunks.
tts_voice_listClient → ServerClient requests available TTS voices.
tts_voice_list_resultServer → ClientServer returns available TTS voices.
errorServer → ClientServer emits error messages.

Messages

TTS request

tts · Client → Server

Content type: application/json

FieldTypeRequiredDescription
idstring (uuid)YesUnique identifier for this TTS request (echoed in responses).
textstringYesText to synthesize. It must contain at least one Unicode letter or number after trimming whitespace: whitespace-only text is rejected with VALIDATION_REQUIRED_FIELD, and text with no letter or number (for example punctuation-only input such as -, ... or ؟) is rejected with VALIDATION_INVALID_PARAM. Both are emitted as a non-retryable error event carrying the request id, and synthesis is not attempted. Length is counted in Unicode code points, not UTF-8 bytes or displayed grapheme clusters; leading and trailing whitespace is preserved and counts. Inclusive defaults are 500 code points for free accounts and 1,000 for standard and enterprise accounts. Missing or unknown tiers use 500. Deployments can override each tier independently, so no fixed maxLength is stated. Exceeding the limit emits non-retryable CHARACTER_COUNT_EXCEEDED with data.bound tts_input_characters and unit characters. This field is plain UTF-8 text, not SSML; markup is neither parsed nor stripped and counts toward the limit.
modelstringNoTTS model key. If omitted, the service uses its configured default; the code fallback is nebula. Send nebula explicitly for the published path instead of depending on deployment configuration.
voice_idstring (uuid)NoOptional profile UUID returned by tts_voice_list_result. The Arabic variant is selected when text contains an Arabic-script letter; otherwise the English variant is selected. Physical variant IDs are internal and are rejected. voice_id and voice_references are mutually exclusive: supplying both emits a non-retryable VALIDATION_INVALID_PARAM error, and an explicit empty voice_references array counts as supplying it. voice_references: null does NOT count, so voice_id with null is valid. If neither is sent, voice selection is deployment/model-defined.
voice_referencesTTSVoiceReference[] | nullNoOptional single voice reference used for voice adaptation. The current public route consumes only the first item, and the maxItems: 1 bound is enforced at runtime: supplying more emits a non-retryable VOICE_REFERENCE_COUNT_EXCEEDED error with data.bound tts_voice_reference_count. Omitting the field, or sending null, both mean "no reference"; null is accepted for client compatibility because many clients serialize an unset optional field that way, and it is declared in the type union rather than merely tolerated. An explicit empty array is a well-formed array that violates minItems: 1 and so emits VALIDATION_INVALID_PARAM. voice_references and voice_id are mutually exclusive, but null is not a second selector: voice_id together with voice_references: null is valid and uses voice_id.

TTSVoiceReference

FieldTypeRequiredDescription
audiostringYesStandard-base64 RIFF/WAVE audio containing non-empty mono PCM16 data. The base64 must be strictly canonical: line breaks, spaces, the URL-safe alphabet and non-zero padding bits are all rejected with VALIDATION_INVALID_FORMAT, as is anything that is not mono PCM16 RIFF/WAVE. Decoded size must not exceed the deployment's byte ceiling (default 2 MiB) - exceeding it emits PAYLOAD_TOO_LARGE with data.bound tts_voice_reference_bytes. Decoded duration must not exceed the duration ceiling (default 15 seconds, matching the deployed model's own reference limit) - exceeding it emits AUDIO_DURATION_EXCEEDED with data.bound tts_voice_reference_duration. Duration is computed from the file's own declared sample rate. Both bounds are inclusive.
textstringYesTranscript of the reference audio, counted in Unicode code points. It must contain at least one Unicode letter or number. Missing or whitespace-only text emits VALIDATION_REQUIRED_FIELD; text with no letter or number emits VALIDATION_INVALID_PARAM; exceeding the ceiling emits CHARACTER_COUNT_EXCEEDED with data.bound tts_voice_reference_text_characters. This ceiling is independent of the per-tier text limit and does not consume it.

Examples

Basic TTS request

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "text": "Hello from HUMAIN Voice",
  "model": "nebula"
}

TTS request with a specific voice profile

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "text": "Hello from HUMAIN Voice",
  "model": "nebula",
  "voice_id": "19965876-8cd6-4b8c-9af4-35cbec69ff1d"
}

TTS request using voice references

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "text": "Hello",
  "model": "nebula",
  "voice_references": [
    {
      "audio": "UklGRiYAAABXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAAZGF0YQIAAAAAAA==",
      "text": "Reference text"
    }
  ]
}

TTS audio stream

tts_audio · Server → Client

Raw binary audio stream chunks for TTS.

Content type: application/octet-stream

Raw unencoded binary buffer sent as a Socket.IO binary event (tts_audio).

Client should:

  1. Read request id from bytes 0..15.
  2. Check end_of_stream in byte 16 (bit 0).
  3. Append bytes 17..end to an output buffer until end_of_stream=1.

Audio bytes format (bytes 17..end):

  • PCM16 little endian @ 24 kHz, mono (raw waveform; no WAV header).

Byte layout (offsets in bytes):

  • 0..15: id (UUID, 16 bytes)
  • 16: header (uint8)
    • bit 0: end_of_stream (final chunk)
    • bits 1-7: reserved (0)
  • 17..end: audio bytes

Example packet strings are illustrative notation. Spaces and <audio-bytes> are not transmitted.

Examples

Non-final audio chunk

12ab34cd56ef789012ab34cd56ef7890 00 <audio-bytes>

Final audio chunk

12ab34cd56ef789012ab34cd56ef7890 01 <audio-bytes>

TTS voice list request

tts_voice_list · Client → Server

Content type: application/json

FieldTypeRequiredDescription

Examples

Request all available voices

{}

TTS voice list result

tts_voice_list_result · Server → Client

Content type: application/json

Type: TTSVoiceListResult

List of available TTS voices.

Examples

List of available voice profiles

[
  {
    "id": "af52a907-1086-46f7-8f5d-72317875d7bd",
    "label": "mul_youssef",
    "profile": {
      "speaker": {
        "gender": "male",
        "dialect": "arz"
      },
      "languages": [
        "ar",
        "en"
      ]
    }
  }
]

No voices returned

[]

Error message

error · Server → Client

Content type: application/json

FieldTypeRequiredDescription
idstring (uuid)NoTTS request UUID (present when parseable from the payload)
codestringYesMachine-readable error code
messagestringYesHuman-readable error text
retryablebooleanYesWhether the client should retry
timestampstring (date-time)YesUTC RFC 3339 timestamp created when the error is emitted.
retry_after_secondsintegerNoSeconds to wait before retrying. Present only on a retryable limit rejection. This transport has no Retry-After header, so the hint travels in the frame.
dataobjectNoPresent only on limit rejections. Names the bound that was exceeded, its configured value and the observed value.

Examples

Invalid JSON payload

{
  "code": "VALIDATION_INVALID_FORMAT",
  "message": "invalid json body provided",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

The account already has as many concurrent TTS syntheses in flight as its plan allows, counted across every server instance. The limit is per BILLABLE ACCOUNT, so several API keys belonging to one account share one allowance. Retryable: it usually clears within seconds. The connection is NOT closed - other operations already admitted on this socket keep running.

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "CONCURRENCY_LIMIT_EXCEEDED",
  "message": "too many concurrent operations for this account",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z",
  "retry_after_seconds": 5,
  "data": {
    "limit": 4,
    "observed": 4,
    "unit": "operations",
    "bound": "account_concurrency_tts"
  }
}

Text is empty or contains only Unicode whitespace

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "VALIDATION_REQUIRED_FIELD",
  "message": "TTS input must contain non-whitespace text",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Text has no letter or number (punctuation-only)

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "VALIDATION_INVALID_PARAM",
  "message": "TTS input must contain at least one letter or number",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Text rejected by the TTS content policy

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "TTS_INPUT_NOT_ALLOWED",
  "message": "TTS input is not allowed",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Content-moderation authority temporarily unavailable

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "TTS_MODERATION_UNAVAILABLE",
  "message": "TTS moderation is unavailable",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z"
}

Text exceeds the default free-tier runtime limit

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "CHARACTER_COUNT_EXCEEDED",
  "message": "TTS input contains 501 characters; limit is 500",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 500,
    "observed": 501,
    "unit": "characters",
    "bound": "tts_input_characters"
  }
}

More than the published maxItems of 1

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "VOICE_REFERENCE_COUNT_EXCEEDED",
  "message": "voice_references contains 2 references; limit is 1",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 1,
    "observed": 2,
    "unit": "references",
    "bound": "tts_voice_reference_count"
  }
}

voice_id and voice_references were both supplied

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "VALIDATION_INVALID_PARAM",
  "message": "voice_id and voice_references are mutually exclusive",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Decoded reference audio exceeds the per-reference byte ceiling

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "PAYLOAD_TOO_LARGE",
  "message": "voice_references[0].audio decodes to 3145728 bytes; limit is 2097152",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 2097152,
    "observed": 3145728,
    "unit": "bytes",
    "bound": "tts_voice_reference_bytes"
  }
}

Reference clip longer than the deployed model's reference limit

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "AUDIO_DURATION_EXCEEDED",
  "message": "voice_references[0].audio is 16 seconds long; limit is 15",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 15,
    "observed": 16,
    "unit": "seconds",
    "bound": "tts_voice_reference_duration"
  }
}

Reference transcript exceeds its own independent limit

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "CHARACTER_COUNT_EXCEEDED",
  "message": "voice_references[0].text contains 501 characters; limit is 500",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 500,
    "observed": 501,
    "unit": "characters",
    "bound": "tts_voice_reference_text_characters"
  }
}

Synthesis did not complete within the overall deadline

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "TTS_DEADLINE_EXCEEDED",
  "message": "TTS synthesis deadline exceeded",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z"
}

voice_id is present but not a valid UUID (SAU-2258)

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "VALIDATION_INVALID_UUID",
  "message": "voice_id must be a valid UUID",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

voice_id is a valid UUID but does not identify an available voice (SAU-2258)

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "TTS_VOICE_NOT_FOUND",
  "message": "voice_id does not identify an available voice",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Resolved voice has incomplete/corrupt stored data; non-retryable (SAU-2258)

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "TTS_VOICE_RESOLUTION_FAILED",
  "message": "selected voice could not be resolved",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

Transient database/storage outage while resolving voice_id; retryable (SAU-2258)

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "code": "SERVER_DEPENDENCY_FAILURE",
  "message": "voice resolution is temporarily unavailable",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z"
}

On this page