# HUMAIN Voice Docs
---
---
# Authentication
Locale: en
Source: https://docs.voice.humain.com/en/authentication
Use your organization's approved access flow to obtain an API key and the
connection values configured for your environment.
## Before you begin
Have these prerequisites ready:
| Requirement | Purpose |
|---|---|
| A trusted server-side runtime | Keeps the API key out of browser and mobile code |
| `curl` | Runs the non-mutating diagnostic request below |
| Your organization's access flow | Provides the configured connection values and credential |
## Obtain credentials
Obtain and configure these values through your organization's approved access
flow:
- `API_KEY`: the credential for protected operations, with the speech
capabilities your integration needs.
- `API_URL`: the service URL provisioned for the environment.
- `API_PATH`: an optional Socket.IO path override. The released SDK defaults to
`/socket.io`; the legacy `sautech.humain.com` endpoint is not consolidated
and still requires `/realtime/socket.io`.
Do not guess a URL or path from another environment. Use only the values
configured for the environment where the integration runs.
## Store credentials
For a local Bash session, set the non-secret values and read the key without
echoing it or placing it in shell history:
```bash
export API_URL="https://api.voice.humain.com"
read -rsp "HUMAIN Voice API key: " API_KEY
export API_KEY
printf '\n'
```
In a deployed service, inject `API_KEY` from a secret manager or protected
environment variable. Keep it out of source control, client-exposed environment
variables, URLs, logs, screenshots, and support messages. Do not print the
variable to confirm that it is set.
Set `API_PATH` only when your deployment overrides the SDK's `/socket.io`
default. The legacy `sautech.humain.com` endpoint requires
`/realtime/socket.io`. Batch REST does not use it.
## Send Origin on Socket.IO
The Socket.IO handshake requires `Origin` even from non-browser clients that do
not set it automatically. Send the scheme and host of the service URL
provisioned for your environment.
SDK `0.18.0` derives `Origin` from `api_url` and sets it on the Socket.IO
handshake. A direct Socket.IO client must send the header itself, set to the
scheme and host of `API_URL`. Batch REST and Realtime HTTP require `x-api-key`;
their published OpenAPI contract does not require `Origin`.
## Run a non-mutating diagnostic
Check the configured route and credential without uploading audio or opening a
stream.
### Read a deliberately unknown Batch job
Read a syntactically valid job ID that is not associated with a real job:
```bash
curl -sS -i \
"$API_URL/v1/transcribe/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: $API_KEY"
```
This request does not upload audio or create a job. Record the status and body
as diagnostic evidence from the configured request path. The public contract
does not guarantee the evaluation order between authentication, authorization,
and job lookup, so a `404` is not by itself proof that the credential and Batch
capability are valid. Handle `401` and `403` with the corrective actions below.
Avoid `curl -v` in shared terminals or logs: verbose request output includes
the `x-api-key` header.
## Send credentials
### HTTP operations
Send `x-api-key` on every protected Batch REST or Realtime HTTP request:
```bash
curl -X POST "$API_URL/v1/transcribe/codeswitch?asr=bayan_cs_ar_en" \
-H "x-api-key: $API_KEY" \
-F "file=@meeting.wav"
```
Every currently published Batch REST and Realtime HTTP operation requires the
`x-api-key` header.
### Socket.IO connections
From a trusted Node.js or Bun runtime, send both headers during the Socket.IO
handshake and use the provisioned path:
```ts
import { io } from "socket.io-client";
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!,
},
});
```
The released SDK clients configure this handshake from `api_url` and `api_key`;
`api_path` is optional and defaults to `/socket.io`. They derive `Origin` from
the configured `api_url`. Prefer them unless you need direct protocol control.
## Resolve rejected credentials
Branch on the HTTP status first. Parse a machine-readable `code` when the
response contains a structured platform error, and preserve an unstructured
gateway or authentication response for diagnosis. Do not branch on message
text.
| Signal | Meaning | Action |
|---|---|---|
| `401`, with or without `AUTH_UNAUTHORIZED` | The key is missing, empty, or invalid for the request path. | Confirm that the trusted runtime received the configured value and sent `x-api-key`, without printing it. If the configuration should work, follow your organization's approved access flow for a corrected credential. Do not retry the unchanged request. |
| `403` with `AUTH_FORBIDDEN` | Access to the requested operation was denied. | Confirm that you are calling the intended service, then use your organization's approved access flow to resolve the required capability. Do not retry until the credential, access, or operation changes. |
| Other `403` response | A gateway or another intermediary rejected the request. | Preserve the response and support identifier, if present, then verify the configured URL, route, and credential through the approved access flow. |
Socket.IO can reject the connection or emit an `error` event, depending on
when validation fails. Stop sending audio, check the same environment values
and capability, then reconnect only after correcting the configuration.
## Respond to an exposed or unused key
If a key appears in source control, client code, a URL, a log, or another
untrusted location, treat it as exposed:
1. Stop using the key and remove it from active configuration and exposed
locations. Deleting one visible copy does not make the key safe again.
2. Report the exposure through your organization's approved access flow without
including the credential in the report, and follow the response instructions
provided there.
3. If a replacement is issued, update the server-side secret and restart or
redeploy every trusted runtime that used the old value.
4. Remove stale copies from secret stores and deployment configuration, then
test a representative operation with the active configuration.
For an unused key, stop using it and follow the same approved access flow for
the organization's retirement procedure.
## Next steps
After the diagnostic produces the response expected for your configured
environment, complete a first transcription with the SDK quickstart or review
direct transport behavior.
---
# Concepts
Locale: en
Source: https://docs.voice.humain.com/en/concepts
Start with two questions: is the input audio or text, and—if it is audio—is the
whole unit already available? Those answers choose the processing model.
Transport and SDK client come afterward.
## Choose the processing model
| Starting point | Choose | Behavior | Decision boundary |
|---|---|---|---|
| A complete long-form or large recording | **Batch transcription** | Upload once, receive a `jobId`, and poll a job | Use for meetings, podcasts, archives, and other work where asynchronous completion is acceptable. |
| A complete audio unit whose latency matters | **Fast transcription** | Send the whole encoded audio unit over Socket.IO, then receive result events | Use for bounded full-audio work such as one agentic or conversational turn. It is not live audio streaming and is not the long-recording path. |
| Audio that is still arriving | **Realtime transcription** | Send PCM16 chunks and receive provisional and final text while the stream is open | Use for calls, captions, microphones, and live media pipelines. |
| A need to know who spoke when | **Diarization** | Produce speaker time segments alongside batch audio or from a live PCM stream | Add it to the matching batch or live workflow; it does not produce the transcript itself. |
| Text that must become audio | **Text-to-speech (TTS)** | Send text and receive streamed raw PCM samples | Use when speech is the output rather than the input. |
The decisive distinction is the input boundary. Batch and fast transcription
both start with complete audio; fast result events do not make the input
realtime. If audio is still being produced, choose realtime.
## Batch is a job
Batch submission returns `jobId`. Poll the result route until a terminal state
or until the app's overall deadline expires.
| Status | State | App decision |
|---|---|---|
| `queued` | Non-terminal | Wait, then poll again within the deadline. |
| `processing` | Non-terminal | Keep waiting within the same deadline. |
| `done` | Terminal success | Read the completed result. |
| `failed` | Terminal failure | Stop polling and surface the job failure. |
| `cleared` | Terminal without a stored result | Stop polling and treat the result as unavailable. |
The published API does not define a retention duration, so do not design around
a guaranteed result-availability window. SDK `0.18.0` succeeds on `done`, raises
on `failed`, and otherwise stops at its configured timeout; a direct poller must
handle `cleared` itself.
Result retrieval defaults to `save_result=false`. A terminal `done` or `failed`
read can clear stored fields after building its response, so a lost response
can be followed by `cleared`. Set `save_result=true` before polling when
terminal delivery must be repeatable; that setting still defines no retention
duration.
## Event results are state, not a transcript log
Fast, realtime, and diarization responses evolve. Reconcile them by request or
stream ID instead of appending every event.
| Surface | Result markers | State rule |
|---|---|---|
| Fast transcription | `id`, `seq`, `is_final` | Treat non-final responses as provisional and commit the final response once. |
| Realtime transcription | `id`, `seq`, `is_final`, `is_speech_final` | Replace provisional text while both final flags are false; commit when either becomes true. |
| Live diarization | `id`, `final_segments`, `active_segments`, `is_final` | Accumulate unseen final additions and replace the revisable active tail. |
Fast and Realtime responses contain `seq`, but their current public contracts
do not define ordering or uniqueness semantics for it. Route events by `id`,
process them in observed arrival order, and treat each event's text and words as
that event's state. Finish only on the capability's final signal or an
error/deadline.
`RealtimeSubtitles` intentionally ignores provisional responses and
deduplicates finalized responses by stream ID and `seq`. Because the current
Realtime wire contract does not promise distinct `seq` values, do not use that
helper to collect multiple final events. Collect finalized words in observed
arrival order and render them with `Subtitles` instead.
End a live input with the documented final frame, wait only to an app
deadline, and always clean up the client. A close wait expiring does not prove a
final result arrived; inspect the state recorded by callbacks.
## Build a speaker timeline
Diarization produces relative speaker labels over time, not real-world speaker
identity. Live SDK updates expose the reconciled timeline as `update.segments`
and new final additions as `update.newlyFinalized` /
`update.newly_finalized`. Closing the SDK stream waits up to five seconds and
returns the best-known timeline if no final update arrives in that time.
In the batch V2 response, `final_word_segments` and `diarization_segments` are
separate. If the app needs speaker-attributed words, document an explicit
overlap rule rather than assuming every word already contains `speaker`.
## Audio and transport contracts
| Surface | Audio contract | SDK `0.18.0` transport |
|---|---|---|
| Batch transcription | Complete supported audio-file container | REST |
| Fast transcription | One complete AAC, FLAC, MP3, MP4, or WAV file | Socket.IO |
| Realtime transcription and live diarization | PCM16 little-endian, 16 kHz, mono | Socket.IO |
| TTS through the SDK | Raw PCM16 little-endian, 24 kHz, mono output | Socket.IO |
| Direct HTTP TTS | Undelimited protocol capture with conceptual 16 kHz PCM16 service frames; not generically decodable audio | No public SDK wrapper |
Raw PCM is not a media-file container. A typical player needs a WAV header with
the matching sample rate. Direct integrations can also use the validated
Realtime HTTP operations; no public SDK `0.18.0` client wraps them.
## Next steps
Concepts explain what to choose. The SDK guides define released client behavior;
recipes assemble complete tasks; OpenAPI and AsyncAPI define direct wire
contracts.
---
# Introduction
Locale: en
Source: https://docs.voice.humain.com/en
HUMAIN Voice turns complete recordings or live audio into text and generates
speech from text. Start here to choose one workflow; the
[Quickstart](/en/quickstart) owns installation and first-request instructions.
## Choose by audio and outcome
| What you have or need | Use | Start here |
|---|---|---|
| A meeting, podcast, or other complete long recording | **Batch transcription** uploads the file and polls for a terminal result. | [Quickstart](/en/quickstart) |
| A complete audio unit that needs a latency-sensitive result, such as one agentic conversational turn | **Fast transcription** sends the full audio over Socket.IO. It is not live microphone streaming and is not the path for long recordings or podcasts. | [SDK guide](/en/sdk) |
| Audio still being produced by a microphone, call, or media pipeline | **Realtime transcription** streams PCM16 and returns provisional and final results. | [Quickstart](/en/quickstart) |
| Text that must become playable speech | **Text-to-speech** returns PCM16; the recipe writes the WAV container. | [TTS-to-WAV recipe](/en/recipes/text-to-speech-to-file) |
| A runtime without a released SDK, or wire-level control | **Direct API** uses REST, HTTP streaming, or Socket.IO from a trusted backend. | [API Guides](/en/api-guides) |
If the audio already exists and you are unsure, choose batch. Choose realtime
only when results must arrive while audio is still being produced.
## Before you start
- These docs target **JavaScript and Python SDK `0.18.0`**.
- Obtain `API_KEY` through your organization's [access flow](/en/authentication).
This site renders the `API_URL` configured for its environment.
- Socket.IO clients default to `/socket.io`; pass `API_PATH` only when a
deployment uses an override. The legacy `sautech.humain.com` endpoint
requires `/realtime/socket.io`. Keep the API key in a trusted server
environment.
The [Quickstart](/en/quickstart) covers pinned installation, audio preparation,
environment variables, and the first tested batch and realtime requests.
## From first request to production
1. Complete the [Quickstart](/en/quickstart) for batch or realtime.
2. Use the language-specific [SDK guide](/en/sdk), or use
[API Guides](/en/api-guides) for a direct integration.
3. Add speaker labels, subtitles, or playable TTS output from
[Recipes](/en/recipes).
4. Handle structured errors, deadlines, and bounded retries with
[Errors and Rate Limits](/en/api-guides/errors-and-rate-limits).
## Machine-readable access
- [`/llms.txt`](/llms.txt) lists documentation entry points;
[`/llms-full.txt`](/llms-full.txt) contains the complete Markdown bundle.
- Narrative Markdown uses `/en/md/`, for example
[`/en/md/quickstart`](/en/md/quickstart).
- Generated API-reference Markdown uses `/en/api-reference/md/`.
---
# Models, Languages, and Voices
Locale: en
Source: https://docs.voice.humain.com/en/models
Choose the processing workflow first. Then choose only the parameters that
workflow exposes: language identifies the speech, an ASR model selects a
recognizer, processing selectors modify batch output, and a TTS voice is not a
model.
## Make the choices in this order
1. Choose **batch** for long-form or large complete recordings, **fast** for a
complete latency-sensitive audio unit such as an agentic turn, **realtime**
while audio is still arriving, or **TTS** when text is the input.
2. For speech-to-text, choose the `Language` value that describes the audio.
3. For batch or fast transcription, choose a pipeline-specific ASR model when
the operation requires or your integration intentionally pins one. Realtime
transcription selects language, not an ASR model.
4. Add batch processing selectors only when needed. For TTS, choose the model
and then a runtime voice or voice references.
| Choice | What it controls | What it does not control |
|---|---|---|
| Language | Arabic, English, or Arabic-English code-switching input | The specific recognizer implementation |
| ASR model | Recognizer used by batch or fast transcription | Realtime language framing or TTS |
| Processing selector | Diarization, redaction, or ITN on a batch job | The ASR model itself |
| TTS model | Speech-synthesis engine | The voice identity |
| Voice | A listed voice ID or caller-supplied references | The TTS engine |
These tables document constants exported by JavaScript and Python SDK `0.18.0`.
An exported constant does not guarantee that a model or voice is provisioned for
every key or environment. Use the configuration issued for your environment and
handle model-unavailable and empty-voice-list results.
## Language values
The same `Language` members are exported in JavaScript and Python.
| SDK constant | Wire value | Realtime frame byte | Used by |
|---|---|---|---|
| `Language.Ar` | `ar` | `0` | Batch path, fast metadata, realtime frames |
| `Language.En` | `en` | `1` | Batch path, fast metadata, realtime frames |
| `Language.ArEn` | `codeswitch` | `2` | Batch path, fast metadata, realtime frames |
| — (direct wire only) | `auto` | `255` | Batch path, fast metadata, realtime frames |
`auto` selects the automatic default configured for the environment, which
currently resolves to the code-switching model. It is a direct-wire value: SDK
`0.18.0` exports no named constant for it, so reach it only through a direct
OpenAPI or AsyncAPI integration. Omitting the language where the operation
allows it has the same effect.
For direct HTTP operations, use the language values declared by the relevant
OpenAPI operation. Do not pass a batch or fast model enum to
`RealtimeClient.startStream()` / `start_stream()`.
## ASR models for batch and fast transcription
JavaScript and Python `0.18.0` use the same member names and wire strings.
| Wire value | Batch constant | Fast constant | Released SDK constraint |
|---|---|---|---|
| `nida_ar` | `BatchTranscriptionModel.NidaAr` | `FastTranscriptionModel.NidaAr` | Arabic-labelled model |
| `nida_8k_ar` | `BatchTranscriptionModel.NidaArTelephony` | — | Exported only for batch in `0.18.0` |
| `bayan_ar` | `BatchTranscriptionModel.BayanAr` | `FastTranscriptionModel.BayanAr` | Arabic-labelled model |
| `bayan_cs_ar_en` | `BatchTranscriptionModel.BayanArEn` | `FastTranscriptionModel.BayanArEn` | Unversioned Arabic-English alias |
| `bayan_cs_ar_en_v1` | `BatchTranscriptionModel.BayanArEnV1` | `FastTranscriptionModel.BayanArEnV1` | Fixed Arabic-English version |
| `bayan_cs_ar_en_v2` | `BatchTranscriptionModel.BayanArEnV2` | `FastTranscriptionModel.BayanArEnV2` | Fixed Arabic-English version |
| `fast_en` | `BatchTranscriptionModel.FastEn` | `FastTranscriptionModel.FastEn` | English-labelled model |
The compatibility `ASRModel` enum contains all seven members, but new code
should use `BatchTranscriptionModel` or `FastTranscriptionModel` so an invalid
pipeline combination is harder to express. The SDK surface does not define a
quality or latency ordering between `NidaAr` and `BayanAr`; follow the model
configuration provided for your environment.
### Defaults, aliases, and compatibility
| Case | Released `0.18.0` behavior |
|---|---|
| Batch ASR omitted | `asr` is optional; the request leaves model selection to the service. |
| Fast ASR | `FastTranscriptionClient.transcribe()` requires a model and a language; it still sends one complete audio unit. |
| Realtime ASR | `startStream()` / `start_stream()` requires a language and has no ASR-model parameter. |
| Arabic-English alias | Use the unversioned `BayanArEn` compatibility alias; choose `BayanArEnV1` or `BayanArEnV2` only when intentionally pinning that wire value. |
| Telephony constant | `NidaArTelephony` is intentionally absent from `FastTranscriptionModel`; treat that as a `0.18.0` compatibility constraint, not a permanent platform-availability statement. |
Fast transcription shares language and model selection with batch, but not its
workload boundary: fast consumes a complete latency-sensitive audio unit;
meetings, podcasts, archives, and other long-form recordings belong to batch.
## Batch processing selectors
Selectors modify processing; they do not replace `Language` or the ASR model.
| Purpose | SDK constant or option | Outgoing value | Meaning |
|---|---|---|---|
| Diarization | `BatchDiarization.Off` | `0` | Turn off speaker segmentation |
| Diarization | `BatchDiarization.On` | `1` | Enable the default diarization selection |
| Diarization | `BatchDiarization.D1` | `d1` | Select diarization key `d1` |
| Diarization | `BatchDiarization.D2` | `d2` | Select diarization key `d2` |
| Redaction | `BatchRedact.Off` | `0` | Turn off redaction |
| Redaction | `BatchRedact.On` | `1` | Enable redaction |
| ITN | `itn: boolean` | `true` / `false` in SDK requests | Toggle inverse text normalization |
Omitting a selector omits that query parameter; do not present an omitted value
as a stable processing default. For direct REST, use the accepted values in the
current OpenAPI operation rather than copying SDK serialization. In Python,
`BatchDiarization` and `BatchRedact` are exported from
`humain_voice.stt.batchtranscription`, not the top-level `humain_voice.stt`
namespace.
## TTS model and voice
| Choice | SDK surface | Value or rule |
|---|---|---|
| Model | `TtsModel.Nebula` | Wire value `nebula`; this is the SDK `0.18.0` default when `model` is omitted. |
| Listed voice | `VoiceInfo` with `id`, `label`, and `profile` | Call `listVoices()` / `list_voices()` and pass the returned profile `id` as `voice_id`. |
| Voice references | `VoiceReference` with `audio` and `text` | For the public route, supply one standard-base64 RIFF/WAVE reference containing non-empty mono PCM16 data and its transcript instead of `voice_id`. |
A synthesis request requires exactly one of `voice_id` or non-empty
`voice_references` in SDK `0.18.0`; neither is a model constant. The direct wire
contract permits neither selector, in which case voice selection is
deployment/model-defined and no voice is guaranteed. Handle an empty voice list
instead of guessing an ID. The documentation examples pass a five-second
voice-list timeout in both languages; Python has no default timeout, while
JavaScript defaults voice listing to five seconds.
Socket.IO TTS for `TtsModel.Nebula` returns raw PCM16 little-endian, 24 kHz,
mono audio. Use `getSampleRate()` / `get_sample_rate()` when writing a container.
### Voice identities and labels
The voice list contains only the seven multilingual profiles. Every item has
`profile: { speaker: { gender, dialect }, languages }` and a stable profile ID
such as the ID labeled `mul_youssef`. Send that ID as `voice_id`; Platform keeps
the physical variants internal and rejects their IDs when supplied directly.
For the current Arabic/English profiles, any Unicode Arabic-script letter in
`text` selects Arabic. Otherwise English is selected. Numbers, punctuation,
emoji, whitespace, and letters from non-Arabic scripts do not select Arabic.
Treat every `label` as a human-readable hint only. Render the structured
`profile` metadata, store the stable `id`, and never derive or match on `label`.
## Next steps
---
# Quickstart
Locale: en
Source: https://docs.voice.humain.com/en/quickstart
The shortest path to a first result is **batch transcription** of a complete
audio file. It accepts a supported audio container and does not require you to
prepare realtime PCM chunks. Complete that path first, then choose fast or
realtime delivery if your product needs it.
## Before you start
Have these ready before running a command:
- An API key and Socket.IO path obtained through your organization's
[access flow](/en/authentication). The page renders the base URL configured
for its environment.
- A complete, supported audio file. The examples below use `meeting.wav` and
write captions to `meeting.vtt`.
- One supported SDK runtime:
- JavaScript / TypeScript: a server-side Node.js or Bun runtime that supports
ES2021, `fetch`, `FormData`, and `Blob`. The SDK does not publish a minimum
Node.js or Bun version. The fixtures are checked with Node.js 24 and Bun
1.3.14; the direct `node` commands below assume that Node.js 24 verification
environment.
- Python 3.10 or newer.
- `ffmpeg` only if you plan to try the optional realtime path.
Keep the API key in server-side configuration. Do not put it in browser or
mobile code.
## 1. Install SDK 0.18.0
Choose one language. The page uses the same JavaScript and Python tab labels for
every alternative.
JavaScript / TypeScript
Python
```bash
npm install @humain-voice/sdk@0.18.0
```
```bash
python -m pip install humain-voice==0.18.0
```
**Expected:** the package manager completes successfully and records the exact
SDK version `0.18.0`.
## 2. Configure the environment
Run these exports in the same shell that will run the example. Replace the key
with the value configured for your organization.
```bash
export API_URL="https://api.voice.humain.com"
export API_PATH="/socket.io"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
test -n "$API_URL" && test -n "$API_PATH" && test -n "$API_KEY" && echo "HUMAIN Voice environment ready"
```
**Expected:** the last command prints `HUMAIN Voice environment ready`.
This environment publishes Socket.IO at `/socket.io`. Release `0.18.0`
defaults every Socket.IO client to `/socket.io`. Set
`API_PATH` only when a self-hosted or proxied deployment requires an override.
The legacy `sautech.humain.com` endpoint requires `/realtime/socket.io`.
The batch client uses `API_URL`, `API_KEY`, and `API_VERSION` only.
## 3. Run a batch transcription
Use the code-block copy button and save the selected fixture under its displayed
filename. It submits `meeting.wav`, polls with a five-minute deadline, enables
diarization, prints the returned transcript, and writes WebVTT captions.
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
BatchDiarization,
BatchTranscribeClient,
BatchTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.wav';
const outputPath = process.argv[3] ?? 'meeting.vtt';
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
api_version: process.env.API_VERSION ?? 'v1',
});
try {
const result = await client.transcribe(
await readFile(inputPath),
Language.ArEn,
{
asr: BatchTranscriptionModel.BayanArEn,
diarization: BatchDiarization.On,
saveResult: true,
pollInterval: 2,
timeout: 300,
onProgress: ({ status }) => console.info('status:', status),
},
);
console.info(result.results?.transcript ?? '');
await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.batchtranscription import BatchDiarization
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.vtt")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
api_version=os.environ.get("API_VERSION", "v1"),
) as client:
result = await client.transcribe(
input_path,
lang=stt.Language.ArEn,
asr=stt.BatchTranscriptionModel.BayanArEn,
diarization=BatchDiarization.On,
save_result=True,
poll_interval=2.0,
timeout_seconds=300.0,
on_progress=lambda response: print("status:", response.status.value),
)
print(result.results.transcript if result.results else "")
output_path.write_text(
stt.Subtitles.from_response(result).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
Run the command for the file you saved:
- JavaScript / TypeScript: `node batch-transcription.ts meeting.wav meeting.vtt`
- Python: `python batch_transcription.py meeting.wav meeting.vtt`
**Expected:** on a successful job, the terminal prints one or more `status:`
updates followed by the returned transcript, and `meeting.vtt` is created. Audio
with no recognized speech can produce an empty transcript.
Your first HUMAIN Voice request is complete when the job reaches `done` and the
caption file is written.
## After the first result
- The fixture polls every two seconds with a 300-second polling-loop threshold.
Submission and an in-flight fetch can extend wall time. Choose deadlines for
your own workload; a request timeout is not an overall workflow deadline.
- SDK `0.18.0` returns on `done` and raises on `failed` or timeout. Its
`transcribe()` helper does not stop specially on `cleared`, so a cleared job
reaches the configured timeout. A direct poller must stop on `done`, `failed`,
and `cleared` explicitly.
- The fixture closes its client even when submission or polling fails. Preserve
that cleanup pattern in production.
The [batch recording recipe](/en/recipes/transcribe-a-recording) expands the
polling, speaker-label, and subtitle patterns.
## Choose the next delivery mode
| Mode | Use it when | Audio delivery | Result flow |
|---|---|---|---|
| Batch transcription | A complete recording, including longer meetings, calls, or podcasts | Upload once | Poll a job until `done`, `failed`, or `cleared` |
| Fast transcription | A short, already-complete audio payload needs lower latency, such as one agentic conversation turn | Send the complete payload once over Socket.IO | Receive upload and transcription events, ending with a final result |
| Realtime transcription | Audio is still arriving from a microphone, call, or live source | Send PCM16 little-endian, 16 kHz, mono chunks | Replace provisional text until a final or speech-final response arrives |
Fast transcription is not the long-audio or podcast path. Use batch for those
complete recordings; use fast when the complete payload is short and latency
matters.
## Optional: run realtime transcription
Realtime input must already be raw PCM16 little-endian, 16 kHz, mono. Convert a
recording for this walkthrough:
```bash
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ar 16000 -ac 1 speech.pcm
```
**Expected:** `ffmpeg` exits successfully and creates `speech.pcm`. Raw PCM has
no playable file header.
Save the selected fixture under its displayed filename:
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
type ErrorResponse,
Language,
RealtimeClient,
Subtitles,
type WordSegment,
} from '@humain-voice/sdk';
const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'speech.pcm';
const outputPath = process.argv[3] ?? 'speech.vtt';
const client = new RealtimeClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
const finalizedWords: WordSegment[] = [];
let serverError: ErrorResponse | undefined;
let protocolFinalObserved = false;
try {
const stream = await client.startStream(Language.ArEn, {
onResponse: (response) => {
const kind = response.is_final
? 'final'
: response.is_speech_final
? 'speech-final'
: 'partial';
console.info(`${kind}:`, response.transcription);
if (response.is_final) protocolFinalObserved = true;
if (response.is_final || response.is_speech_final) {
// The current public Realtime contract does not guarantee increasing
// seq values, so collect final words in arrival order instead of
// asking RealtimeSubtitles to deduplicate by id:seq.
finalizedWords.push(...response.words);
}
},
// The released SDK can invoke a stream handler more than once for one
// routed error, so keep this callback idempotent.
onError: (error) => {
serverError = error;
},
});
const pcm = await readFile(inputPath);
for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
await pause(100);
}
// close() sends the last frame and waits for protocol is_final, a routed
// error, or this timeout. It resolves rather than throwing on timeout.
await stream.close(5);
if (serverError) {
throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
}
if (!protocolFinalObserved) {
throw new Error('Realtime stream ended before protocol is_final');
}
await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
CHUNK_BYTES = 3_200 # 100 ms of PCM16LE, 16 kHz, mono audio.
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "speech.vtt")
finalized_words: list[stt.WordSegment] = []
server_error: stt.ErrorResponse | None = None
protocol_final_observed = False
def handle_response(response: stt.RtTranscribeResponse) -> None:
nonlocal protocol_final_observed
if response.is_final:
kind = "final"
elif response.is_speech_final:
kind = "speech-final"
else:
kind = "partial"
print(f"{kind}:", response.transcription)
if response.is_final:
protocol_final_observed = True
if response.is_final or response.is_speech_final:
# The current public Realtime contract does not guarantee increasing
# seq values, so collect final words in arrival order instead of
# asking RealtimeSubtitles to deduplicate by id:seq.
finalized_words.extend(response.words)
def handle_error(error: stt.ErrorResponse | None) -> None:
# The released SDK can invoke a stream handler more than once for one
# routed error, so keep this callback idempotent.
nonlocal server_error
server_error = error
client = stt.RealtimeClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
stream = await client.start_stream(
language=stt.Language.ArEn,
on_response=handle_response,
on_error=handle_error,
)
pcm = input_path.read_bytes()
for offset in range(0, len(pcm), CHUNK_BYTES):
await stream.send(pcm[offset : offset + CHUNK_BYTES])
await asyncio.sleep(0.1)
# close() sends the last frame and waits for protocol is_final, a routed
# error, or this timeout. It returns rather than raising on timeout.
await stream.close(timeout_seconds=5.0)
if server_error is not None:
raise RuntimeError(server_error.message or server_error.code or "Realtime stream failed")
if not protocol_final_observed:
raise RuntimeError("Realtime stream ended before protocol is_final")
output_path.write_text(
stt.Subtitles.from_words(finalized_words).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
Run the command for the file you saved:
- JavaScript / TypeScript: `node realtime-transcription.ts speech.pcm speech.vtt`
- Python: `python realtime_transcription.py speech.pcm speech.vtt`
**Expected:** the terminal labels responses as `partial:`, `final:`, or
`speech-final:`, and the successful stream writes finalized captions to
`speech.vtt`.
After success, keep provisional UI text separate and replace it as result events
arrive. The fixture collects words only from final or speech-final events, then
uses `Subtitles` to render them; it does not rely on `seq`, whose ordering is not
part of the current Realtime wire contract. It closes the stream, waits up to
five seconds for protocol-level `is_final`, and disconnects the client in
cleanup. A timeout is reported as incomplete instead of writing a normal
caption file.
## Next steps
Continue with the path that matches your product. Before production traffic,
re-run it with representative inputs and exercise deadlines, terminal states,
disconnects, retries, and cleanup regardless of delivery mode.
---
# Troubleshooting
Locale: en
Source: https://docs.voice.humain.com/en/troubleshooting
This page targets `@humain-voice/sdk@0.18.0` and
`humain-voice==0.18.0`. Diagnose from evidence: capture the status, event,
identifier, and final signal before changing configuration or retrying.
## Diagnose in this order
1. Confirm the installed package is exactly `0.18.0`.
2. Confirm `API_URL` and `API_KEY` are present in the server process.
3. Choose the processing mode from the input you actually have.
4. Reproduce with one small, known input and one request. Turn off concurrent
retries while isolating the failure.
5. Record structured error fields and whether cleanup completed.
Run only the package-version command relevant to your app. The shell
loop reports presence without printing the secret; do not replace it with
`env` or another command that exposes `API_KEY`.
```sh
npm ls @humain-voice/sdk --depth=0
python -c 'from importlib.metadata import version; print(version("humain-voice"))'
for name in API_URL API_KEY; do
if [ -n "$(printenv "$name")" ]; then
printf "%s=set\n" "$name"
else
printf "%s=missing\n" "$name"
fi
done
```
## Choose the correct processing mode
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| A long meeting, podcast, or archive file stalls in fast transcription | Fast transcription was used for long-form media | The entire recording existed before the request and is long-form | Use `BatchTranscribeClient`; poll under a finite deadline |
| A bounded conversational turn has unnecessary streaming complexity | Realtime was used although the complete turn already exists | No audio arrives after the request starts | Use `FastTranscriptionClient` for the already-complete, latency-sensitive unit |
| A microphone or call is repeatedly uploaded as completed files | Batch or fast mode was used while audio is still arriving | Processing must begin before recording ends | Use `RealtimeClient` or `RealtimeDiarizationClient` and send framed PCM as it arrives |
| A complete file is sent as realtime PCM, or PCM is uploaded as a file | Container and stream inputs were confused | Compare the input bytes with the selected operation's contract | Send an encoded file to batch or fast; send headerless PCM16 LE to realtime |
Mode selection does not promise a particular latency. It selects the lifecycle
and input contract that match the task.
## Connection and authentication symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| REST returns `401` or `403` | The key is missing, invalid, or lacks access to the operation | Record the HTTP status and structured `code`; confirm only that `API_KEY` is set | Send the provisioned value as `x-api-key` or `api_key`; resolve invalid or access-denied credentials through your organization's approved access flow |
| A Socket.IO constructor says URL or key is required | `api_url` or `api_key` is empty | Log the option names and presence, never the key value | Supply the provisioned `API_URL` and `API_KEY`; `api_path` defaults to `/socket.io` |
| Socket.IO raises `connect_error` or never calls the connection handler | The host or path is wrong, the WebSocket upgrade is blocked, or the handshake is rejected | Compare `API_URL` and the effective `/socket.io` path with the issued values; in Python, reproduce once with `verbose=True` and retain the handshake error | Use the default path unless your deployment documents an override, keep WebSocket transport enabled, and configure the proxy to preserve the upgrade |
| REST works but every Socket.IO capability fails | The Socket.IO route or WebSocket upgrade is blocked | A protected REST call succeeds while the Socket.IO handshake fails before any app event | Test `/socket.io` from the same server network; set `API_PATH` only for a documented override |
| A Socket.IO handshake is rejected before any app event | Its required `Origin` header is missing or does not match the service origin | Compare the sanitized handshake headers; the body can be a gateway page rather than a structured platform error | Set `Origin` to the scheme and host of `API_URL`. A direct Socket.IO client must set it; SDK `0.18.0` derives it from `api_url`. |
| A hand-built Socket.IO client connects differently from the SDK | The path, API-key header, or transport differs | Inspect the sanitized handshake: path, transport, and `x-api-key` presence | Send `x-api-key`, select `transports: ["websocket"]`, and register handlers before connecting |
Release `0.18.0` defaults Socket.IO to `/socket.io`; use `API_PATH` only for a
documented override. The legacy `sautech.humain.com` endpoint requires
`/realtime/socket.io`. Keep credentials in a server-side process; moving a key
into a browser or mobile bundle is not a connection fix.
## Audio and framing symptoms
Inspect an encoded source, then create the exact raw realtime input when
needed:
```sh
ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,sample_rate,channels,sample_fmt \
-of default=noprint_wrappers=1 input.wav
ffmpeg -i input.wav -ar 16000 -ac 1 -c:a pcm_s16le \
-f s16le realtime.pcm
```
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| Batch returns `422` with `VALIDATION_FILE_CORRUPT` | The uploaded file is corrupt or unsupported | Run `ffprobe`; retain the status, `code`, and safe file metadata | Decode or transcode to a valid encoded audio file, then retry once as a new submission |
| Fast transcription accepts an upload but produces no useful final result | The complete payload uses an unsupported container or malformed MP4 | Confirm it is AAC, FLAC, MP3, MP4, or WAV; inspect MP4 layout | Send one complete supported file; place the MP4 `moov` atom at the front |
| Realtime text is empty, garbled, too fast, or too slow | A WAV/MP3 container, big-endian samples, wrong sample rate, or wrong channel count was sent as PCM | `ffprobe` the source and inspect the conversion command; PCM payload length must be even | Send headerless PCM16 little-endian, 16 kHz, mono bytes |
| A direct realtime client receives nothing | The 18-byte application header, UUID, flags, or language byte is wrong | Inspect bytes `0..17`; verify one UUID is reused and audio starts at byte `18` | For `audio_stream`, send flags `1` once, `0` between, and `2` once at the end; use the documented language byte |
| Direct live diarization never finalizes | `diarization_stream` framing or the final flag is missing | Verify the same 18-byte header, one UUID, start bit, and final bit | Send PCM16 LE at 16 kHz mono and exactly one final frame; keep the other flag bits zero |
| Updates arrive in an uneven cadence | Payload sizes differ substantially from the tested helpers | Count audio bytes after the 18-byte header | Start with 3,200 audio bytes per realtime ASR frame; the SDK recommends 15,360 bytes per live diarization feed |
The frame sizes are tested cadences, not throughput or latency guarantees. The
SDK constructs headers; inspect them only for a direct wire implementation.
## Language and model symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| Arabic-English speech is recognized as one language | Language and model do not describe code-switching | Log the exact enum values, not only their labels | Use `Language.ArEn` with `BatchTranscriptionModel.BayanArEn` or `FastTranscriptionModel.BayanArEn` |
| Fast transcription is empty with an 8 kHz telephony model | A batch-only model was forced into the fast pipeline | `NidaArTelephony` is absent from `FastTranscriptionModel` in `0.18.0` | Use `BatchTranscriptionModel.NidaArTelephony` with batch; do not pass its wire string to fast |
| An unexpected language behaves as Arabic | An unrecognized string reached the protocol converter | Log the exact value passed to the SDK; unknown strings map to protocol ID `0` in `0.18.0` | Pass `Language.Ar`, `Language.En`, or `Language.ArEn` instead of a free-form label |
| Realtime configuration includes a batch or fast ASR model | Realtime was treated like a file pipeline | Type-check the call; `RealtimeClient.startStream()` / `start_stream()` selects a language, not an ASR model | Remove the model option and pass the correct `Language` value |
| Direct HTTP TTS fails when no model is specified | Only the direct route leaves model selection to the deployment, whose configured default can differ or be unavailable. The SDK always sends `nebula` when you omit `model`, so this cannot occur through `TTSClient` | Record the structured `error` event and the request payload without text if it is sensitive | Send the explicit model key `nebula` on the direct route instead of relying on deployment configuration |
Use the unversioned `BayanArEn` alias for the released code-switching default.
Choose `BayanArEnV1` or `BayanArEnV2` only when you intentionally require that
specific model. See [Models and languages](/en/models).
## Missing final signals and deadline symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| A batch job never returns from the helper | It remains non-terminal, becomes `cleared`, or exceeds the helper deadline | Log every status: `queued`, `processing`, `done`, `failed`, or `cleared` | Use a finite poll deadline; stop on `done`, `failed`, or `cleared`; call `getResult()` / `get_result()` directly when immediate `cleared` handling is required |
| Fast upload acknowledgement arrives but the request never completes | `audio_file_upload_success` was mistaken for transcription completion | Match its `id`, then check for `transcription_result.is_final === true` | Wait only under an app deadline; Python defaults `timeout_seconds` to 60, while JavaScript `0.18.0` has no fast-request timeout option |
| `RealtimeStream.close()` / `close()` returns without protocol `is_final` | Its bounded protocol-final wait expired | Track wire-terminal `is_final`; the default close wait is one second | `is_speech_final` is only an utterance boundary and does not satisfy the SDK helper. Preserve confirmed text and mark the result incomplete. |
| Diarization `close()` returns a timeline without a final update | Its five-second close wait expired | Track the last update's `isFinal` / `is_final`; the returned timeline is the best-known snapshot | Mark it incomplete unless finality was observed; retain the reconciled snapshot and disconnect |
| TTS times out between chunks or never emits its final chunk | The per-chunk inactivity wait expired, or byte `16` bit 0 never arrived | Record the time of each `tts_audio` frame and its `is_last` value | Bound per-chunk inactivity and the whole synthesis separately; JavaScript defaults each chunk wait to 30 seconds, while Python has no default |
An SDK timeout and an application deadline are different. The SDK timeout may
bound a poll, close wait, or next chunk. Your application deadline must bound
the entire operation, including connection, work, finality, and retries. A
timeout never proves that an upload failed or a stream finalized.
## Subtitle and diarization result symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| Live captions repeat provisional text | Every `transcription_result` was appended | Log `id`, arrival order, `seq`, `is_final`, and `is_speech_final` | Keep one replaceable provisional line per `id`; commit only final or speech-final event words |
| `RealtimeSubtitles` keeps only one of several final events | The helper deduplicates by `id:seq`, but the current wire contract does not guarantee distinct `seq` values | Compare final-event count and `seq` values with `RealtimeSubtitles.words` | Collect final-event words in observed arrival order and render them with `Subtitles` after termination |
| Speaker turns repeat, disappear, or jump | Raw `final_segments` and `active_segments` were concatenated | Compare consecutive raw arrays with `update.segments` | Accumulate unseen finalized segments, replace the active tail, sort by start time, or consume the SDK's reconciled `update.segments` |
| Batch words have no speaker even though diarization exists | Word and diarization timelines are separate in the response shape | Inspect `final_word_segments` / word offsets and `diarization_segments` | Reconcile by temporal overlap and define an app rule for gaps or ambiguous overlap; do not invent a speaker silently |
`RealtimeSubtitles` deliberately ignores provisional responses and deduplicates
final responses by `id` and `seq`; that exact behavior is why it can collapse
distinct final events under the current wire contract. Live diarization's
`active_segments` remain revisable until they move into finalized state.
## TTS voice and playback symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| `listVoices()` / `list_voices()` returns `[]` | One or more physical variants needed by the configured profiles are unavailable | Record the array length and any structured `error`; do not index element `0` | Handle the empty state and do not guess a `voice_id`; retry only under a bounded policy |
| Voice discovery waits forever in Python or times out in JavaScript | Timeout defaults differ | JavaScript defaults to five seconds; Python uses no default | Pass `listVoices({ timeoutSeconds: 5 })` or `list_voices(timeout_seconds=5)` explicitly |
| Synthesized bytes do not play in a media player | Socket.IO TTS returns raw PCM, not a WAV file | Confirm the response reached `is_last`; inspect the byte count | Treat bytes as PCM16 LE, 24 kHz, mono and add a correct WAV header with the [tested TTS-to-WAV recipe](/en/recipes/text-to-speech-to-file) |
| JavaScript WAV output is truncated or contains unrelated bytes | A `Uint8Array` view was converted without its offset and length | Compare `byteLength` with the resulting `Buffer.length` | Construct the `Buffer` with the view's `byteOffset` and `byteLength` |
| Code matching on a previously-seen `label` string stops finding a voice | The catalog exposes profile labels such as `mul_` rather than physical variant labels | Inspect the returned `profile` metadata | Match and persist the profile `id`, never `label`; physical variant IDs are rejected |
| A multilingual profile selects the unexpected physical variant | Arabic routing requires an Arabic-script letter in `text` | Check the text for an Arabic-script letter | Any Arabic-script letter selects Arabic; otherwise English is selected |
For direct Socket.IO parsing, each `tts_audio` payload starts with a 16-byte
UUID and one header byte. Append only bytes `17..end`; byte `16` bit 0 is the
final signal.
## Rate-limit and retry symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| Batch raises `BatchTranscribeRateLimitError` or returns `429` | Audio capacity is temporarily unavailable for the request | Inspect `retryAfter` / `retry_after`, `capacity`, `retryable`, and `code` when present | Honor a supplied delay, add exponential backoff with jitter, and cap attempts and total elapsed time |
| `maxRetries` / `max_retries` appears to do nothing | It is deprecated and ignored in `0.18.0` | The SDK emits a deprecation warning for a nonzero value | Implement the bounded retry policy in application code |
| A connection fails after an upload was sent | The outcome is ambiguous | Record whether a job ID or upload acknowledgement was received | Do not blindly upload again; the API publishes no idempotency-key contract, so apply an app duplication policy or escalate with the evidence |
| A Socket.IO `error` says `retryable: true` | The server classified the event as retryable, not guaranteed to succeed | Capture `id`, `code`, `message`, `retryable`, and `timestamp` from `onError` / `on_error` | Use that field as one input to the same bounded policy; do not loop indefinitely |
`capacity` is an operational response field, not a published account quota or
availability guarantee. A Batch status read is repeatable only when
`save_result=true` preserved terminal output before retrieval; the default read
can clear it. An upload whose outcome is unknown remains unsafe to replay. See
[Errors and rate limits](/en/api-guides/errors-and-rate-limits).
## Cleanup and leaked-connection symptoms
| Symptom | Likely cause | Evidence or check | Fix |
|---|---|---|---|
| The process stays alive after work completes | A Socket.IO client or Python HTTP session remains open | Log client creation, final signal, and cleanup once per operation; Python may report an unclosed session | Put cleanup in `finally`; call `FastTranscriptionClient.close()`, `TTSClient.close()`, `RealtimeClient.disconnect()`, or `RealtimeDiarizationClient.disconnect()` as appropriate |
| Connections increase after errors or timeouts | A new client is created before the failed one is closed | Compare connection and disconnection callback counts | Reuse one healthy client where appropriate and close the failed client before retrying |
| A stream ends without cleanup | The result loop exited before `stream.close()` | Record whether the final input and close path ran | Close the stream in `finally`, then disconnect the client if the failure occurred outside normal stream cleanup |
| Python batch warns about an unclosed `aiohttp` session | `BatchTranscribeClient.close()` / `close_sync()` was skipped | Reproduce one request and observe process shutdown | Use the async or sync context manager, or call the matching close method in `finally` |
JavaScript `BatchTranscribeClient.close()` is a compatibility no-op in
`0.18.0`; its requests use `fetch`. The other JavaScript clients own Socket.IO
connections and require their documented cleanup paths.
## Escalate with reproducible evidence
Retry one known input only when the outcome is unambiguous and the policy
allows it. If the problem remains, send your HUMAIN contact a minimal
reproduction and this sanitized record:
```yaml
sdk: "@humain-voice/sdk@0.18.0 | humain-voice==0.18.0"
operation: "batch | fast | realtime | diarization | tts | voice-list"
api_url_host: "host only"
api_path: "Socket.IO path or not-applicable"
started_at_utc: "ISO-8601 timestamp"
request_or_job_id: "UUID if available"
input: "codec, sample_rate, channels, duration, byte_count"
observed: "http_status, event, final_signal"
error: "code, message, retryable, timestamp"
retries: "count and delays"
cleanup: "final frame, stream close, client disconnect"
```
Attach the smallest code sample that reproduces the issue and state the
expected final signal. Do not send the API key, a full Socket.IO URL containing
its query string, or sensitive audio/text without authorization. For an
ambiguous upload, include its UTC window, safe input checksum, and any job or
request ID instead of submitting it again.
These docs do not publish an outage-status URL, retention duration, quota,
availability target, or support response-time guarantee. Escalate credential
and access-scope failures to the key issuer; escalate repeatable protocol or
finality failures with the evidence above.
---
# Batch transcription
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/batch-rest
Use Batch REST when a large or long recording already exists and asynchronous
completion is acceptable. It fits meetings, podcasts, archives, and similar
complete files: upload once, receive a `jobId`, and poll the job to a terminal
state.
Fast transcription also accepts complete audio, but choose it for one
latency-sensitive conversational unit. If audio is still arriving, use a
[realtime workflow](/en/api-guides/realtime) instead.
## 1. Prepare a trusted server
Direct batch requests need the following values and decisions:
| Requirement | What to prepare |
|-------------|-----------------|
| `API_URL` | Use the exact REST base URL issued for your environment; don't infer a host |
| `API_KEY` | Send it as `x-api-key` from a trusted backend, never public client code |
| Complete audio | Upload one file in the `file` field of a `multipart/form-data` body |
| Deadlines | Set a timeout on each request and a finite deadline for the whole job |
Follow the [authentication flow](/en/authentication) to obtain `API_KEY`. This
site renders the `API_URL` configured for its environment. `API_PATH` is a
Socket.IO setting and isn't used by these REST routes.
## 2. Submit a job
Choose the language path and processing selectors before uploading. This
example requests Arabic–English code-switching, speaker diarization, and
inverse text normalization:
```bash
curl --fail-with-body --connect-timeout 10 --max-time 120 \
-X POST "$API_URL/v1/transcribe/codeswitch?asr=bayan_cs_ar_en&diarization=1&itn=1&redact=0" \
-H "x-api-key: $API_KEY" \
-F "file=@meeting.wav"
```
A successful job creation returns HTTP `200`. The validated specification
includes this response:
```json
{
"jobId": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"status": "queued"
}
```
Check the HTTP status before parsing the success shape, then persist `jobId`
with your application work item. It is the handle for subsequent result reads.
### Processing selectors
| Selector | Location | Accepted values | Effect |
|----------|----------|-----------------|--------|
| `lang` | Path | `en`, `ar`, `codeswitch`, `auto` | Selects the transcription language workflow |
| `asr` | Query | Published model wire value | Overrides the model selected for the language |
| `diarization` | Query | `0`, `1`, `d1`, `d2` | Selects speaker diarization |
| `itn` | Query | `0`, `1` | Enables inverse text normalization |
| `redact` | Query | `0`, `1` | Enables redaction |
Use the [model map](/en/models) for published model wire values. Do not invent
a model suffix that the map does not expose.
## 3. Poll the V2 result route with a deadline
Read the direct V2 result with the returned job UUID:
```bash
export JOB_ID=""
curl --fail-with-body --connect-timeout 10 --max-time 15 \
"$API_URL/v1/transcribe/$JOB_ID?save_result=true" \
-H "x-api-key: $API_KEY"
```
`GET /v1/transcribe/{job_id}` returns
`{ "message": "success", "data": … }`. Branch only on `data.status`:
| Status | Application action |
|--------|--------------------|
| `queued` | Wait, then read again while the overall deadline remains |
| `processing` | Keep waiting within the same deadline |
| `done` | Stop polling and consume the completed result fields |
| `failed` | Stop polling and surface the job failure |
| `cleared` | Stop polling; the result is unavailable |
Use this bounded polling sequence:
1. Set one overall deadline before the first result read.
2. Give every GET its own shorter request timeout.
3. Accept only `queued` and `processing` as reasons to wait and poll again.
4. Stop immediately for `done`, `failed`, or `cleared`.
5. Stop locally when the overall deadline expires; don't infer a server-side
terminal state from a client timeout.
Set `save_result=true` before the first poll when delivery of the terminal
response must be repeatable. With the default `false`, a `done` or `failed`
read can clear stored result fields after constructing its response. If that
response is lost, the next read can return `cleared` instead of the result.
The polling interval and deadline are application choices, not service
guarantees. The [recording recipe](/en/recipes/transcribe-a-recording) provides
bounded JavaScript and Python loops.
## 4. Keep V1 and V2 separate
| Route | Intended use | Response shape | Optional result selectors |
|-------|--------------|----------------|---------------------------|
| `GET /v1/transcribe/{job_id}` | Direct V2 result read | Wrapper with `data.final_result`, `data.final_word_segments`, and `data.diarization_segments` | `save_result`, default `false` |
| `GET /v1/transcribe/{job_id}/{lang}` | Legacy V1 and SDK `0.18.0` | `metadata`, `results.transcript`, `results.offsets`, and `diarization_segments` | `save_result`, default `false`; direct HTTP only: `diarization_force_align`, default `true` |
Both shapes use the same five job statuses, but their field names and nesting
differ. Do not mix V2 snake-case word segments with V1 offsets in one type.
On either route, the default `save_result=false` can make a terminal `done` or
`failed` response a single-consumption read. Set it to `true` before polling
when a lost response must be retrievable again. The contract doesn't specify a
result-retention duration, even with `save_result=true`; treat `cleared` as
terminal without assuming recovery is possible.
The V1 `lang` segment is retained for compatibility but the current result
handler does not use or validate it. SDK `0.18.0` sends the submission language;
new direct HTTP clients should use V2.
## 5. Reconcile diarization
V2 `final_word_segments` do not contain `speaker`. When diarization is enabled,
reconcile each word with `diarization_segments` using an application rule you
document, such as assigning the segment that contains the word midpoint. Keep
an unknown speaker when no segment overlaps unless your application explicitly
adopts nearest-segment assignment.
The V1 route can place `speaker` on word offsets. Its direct-only
`diarization_force_align` option changes those offset labels, not the raw
`diarization_segments`; SDK `0.18.0` does not expose it. With the default
`true`, a word whose `startTime` is outside every real segment uses the speaker
at the nearest segment boundary, measured from the word midpoint; ties use the
earlier segment. With `false`, it uses `UNKNOWN_SPEAKER`. With no real segments,
the speaker stays `null`.
Speaker labels describe relative turns in one result; they do not establish a
real-world identity.
## 6. Handle capacity and ambiguous retries
Batch submission can return HTTP `429` with structured error fields and the
remaining capacity in audio seconds at `data.capacity`:
```json
{
"error": "error.rate_limit",
"code": "RATE_LIMIT_EXCEEDED",
"detail": "error.rate_limit",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z",
"data": { "capacity": 120.5 }
}
```
For an explicit `429`, queue or slow producers and retry with bounded attempts,
backoff, and an overall deadline. Use `capacity` for admission decisions; the
contract does not define it as a sleep duration.
A connection failure or timeout after an upload is different: the first request
may already have created a job. The batch contract does not document an
idempotency-key header, so do not blindly resubmit. Record the ambiguous attempt
and retry only under an application policy that explicitly accepts the risk of
a duplicate job. Result GETs can use bounded retries only when
`save_result=true` was set before terminal retrieval; the default destructive
read can become `cleared` after a lost response. See
[Errors and Rate Limits](/en/api-guides/errors-and-rate-limits).
## 7. Continue to reference and production checks
Implement one representative recording first, then keep the generated Batch
API reference beside your code for exact schemas. Before launch, exercise
authentication failures, invalid audio, `429`, polling deadlines, and all three
terminal outcomes.
---
# Errors and rate limits
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/errors-and-rate-limits
On any failure, first preserve the signal, stop the affected work, and decide
whether you know the outcome. Retry only when the operation is safe to repeat,
the structured state permits it, and an app deadline remains.
## 1. Classify where the failure surfaced
| Surface | What you observe | First action |
|---------|------------------|--------------|
| Transport | Connect, read, inactivity, or disconnect failure with no platform response | Treat the outcome as unknown until the operation contract proves it safe to repeat; stop and close the affected transport |
| HTTP | Non-2xx status and usually a structured `ErrorResponse` body | Preserve status and body, then branch on `code` and `retryable` |
| Socket.IO | Structured `error` event with `code`, `message`, `retryable`, `timestamp`, and optional `id` | Stop feeding the routed request or stream before deciding on recovery |
| SDK | Typed batch exception, structured Socket.IO callback, or a generic rejection after projection | Use the richest typed or callback signal available; don't branch on exception text |
A missing response isn't the same as `retryable: true`. A structured
`retryable: true` is also not sufficient by itself: uploads and interrupted
streams can remain unsafe or ambiguous to repeat.
## 2. Preserve HTTP and SDK fields
Protected Batch REST and realtime HTTP operations use the HTTP
`ErrorResponse` shape:
| Field | Meaning |
|-------|---------|
| `error` | Legacy identifier; keep for diagnostics and compatibility |
| `code` | Machine-readable category for app branching |
| `detail` | Optional human-readable detail; don't branch on its wording |
| `message` | Legacy optional message on some authentication responses |
| `job_id` | Optional Batch job or Realtime HTTP stream UUID tied to the failure |
| `request_id` | Optional Batch request-correlation identifier |
| `retryable` | Whether the server classifies this request failure as retryable |
| `timestamp` | Server timestamp |
| `data` | Optional structured limit or validation evidence; preserve its fields and units |
This validated batch example means “fix the multipart body and don't retry it
unchanged”:
```json
{
"error": "error.api.error.multipart.file.missing",
"code": "VALIDATION_REQUIRED_FIELD",
"detail": "error.api.error.multipart.file.missing",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}
```
Always check the HTTP status before selecting a success parser. Preserve a raw
body when structured parsing fails.
SDK `0.18.0` exposes different projections:
| SDK surface | Structured information |
|-------------|------------------------|
| JavaScript batch | `BatchTranscribeError` exposes `statusCode`, `payload`, `code`, `retryable`, `jobId`, `detail`, `timestamp`, `capacity`, and `rawBody`; rate-limit errors add `retryAfter` |
| Python batch | `BatchTranscribeError` exposes `status_code`, `payload`, `code`, `retryable`, `job_id`, `detail`, `timestamp`, `capacity`, and `raw_body`; rate-limit errors add `retry_after` |
| Socket.IO callbacks | SDK `ErrorResponse` preserves optional `id`, `message`, `code`, `retryable`, `timestamp`, `retry_after_seconds`, `data`, `reason`, and `retry_scope` |
| TTS server-error rejection | JavaScript rejects with generic `Error`; Python raises generic `RuntimeError`; the rejection keeps the message only, so record structured fields in `onError` / `on_error` |
| Workload-limit codes | SDK `0.18.0` preserves `data`, classifies the current limit codes, and routes an id-bearing rejection to the active request context. The global callback still fires first; the synthesis call then rejects with its generic message-only error. |
| TTS content-policy codes | SDK `0.18.0` exports `TTS_INPUT_NOT_ALLOWED` and `TTS_MODERATION_UNAVAILABLE`, classifies both as TTS-owned, and routes an id-bearing error to the active synthesis context |
Still pre-validate TTS input before sending and always pass an explicit deadline
(`timeoutSeconds` in JavaScript, `timeout_seconds` in Python). Read `code` and
`data` from the global error callback before the request rejects; the generic
exception keeps only the message.
## 3. Apply the decision table
| Observed state | Outcome interpretation | Action |
|----------------|------------------------|--------|
| `400` or validation code | Request was invalid | Correct UUID, parameters, framing, file, or audio; don't retry unchanged |
| `401` or authentication code | Key is missing or invalid | Fix credentials before another request |
| `403` with `AUTH_FORBIDDEN` | The platform accepted the key but it lacks the capability | Update access through your organization's key-management flow; don't retry unchanged |
| Other `403` response | A gateway or intermediary rejected the request | Preserve the raw body or support identifier, then verify URL, route, credentials, and any deployment-specific header requirements |
| `404` / `TRANSCRIPTION_JOB_NOT_FOUND` | Requested job isn't available under that UUID | Stop polling that UUID and investigate the stored identifier |
| `405` / `METHOD_NOT_ALLOWED` | Path or method is wrong | Correct routing before another request |
| Batch `422` with a validation code such as `VALIDATION_FILE_CORRUPT` | File is unsupported, corrupt, empty, or zero-duration | Correct the input; don't retry the same bytes |
| Batch `422` / `AUDIO_DURATION_EXCEEDED` with `data.bound` `audio_duration` | The audio is valid but decodes to longer than the accepted duration | Split the recording to `data.limit` seconds or less, or submit a shorter file; don't retry unchanged |
| Batch `422` / `FILE_COUNT_EXCEEDED` | Too many parts for one request. `data.bound` says which, and `data.unit` counts it: `file_parts` counts audio files, `multipart_parts` counts every multipart part | For `file_parts`, send at most `data.limit` audio file per request; for `multipart_parts`, keep the whole form within `data.limit` parts; don't retry unchanged |
| Realtime TTS `422` / `CHARACTER_COUNT_EXCEEDED` | Text, or a voice reference's transcript, is longer than its ceiling. `data.bound` says which: `tts_input_characters` or `tts_voice_reference_text_characters` | Shorten the text using `data.limit`; don't retry unchanged |
| Realtime TTS `422` / `VOICE_REFERENCE_COUNT_EXCEEDED` | More than one entry in `voice_references`; exactly one is accepted | Send a single reference; don't retry unchanged |
| Realtime TTS `422` / `AUDIO_DURATION_EXCEEDED` with `data.bound` `tts_voice_reference_duration` | The reference clip is longer than the deployment's configured reference ceiling, which a deployment may set below the model's own limit | Trim the clip to `data.limit` seconds — `data.limit` is authoritative, not any published default; don't retry unchanged |
| Realtime TTS `413` / `PAYLOAD_TOO_LARGE` with `data.bound` `tts_voice_reference_bytes` | The reference clip's decoded size is over the ceiling | Send a shorter or lower-sample-rate clip; don't retry unchanged |
| TTS `400` / `TTS_INPUT_NOT_ALLOWED` | The content policy rejected the text; the same text will not be accepted | Change the text before sending another request; don't retry it unchanged |
| TTS `503` / `TTS_MODERATION_UNAVAILABLE` | The moderation authority could not make a decision, so synthesis failed closed | Do not treat this as a policy rejection. Retry only after bounded backoff and while the application deadline remains |
| `402` / `CREDITS_EXHAUSTED` | Funding is exhausted; an immediate replay cannot restore it | Stop the affected work and don't retry unchanged. A mid-stream realtime event is terminal and is followed by disconnect. |
| `503` / `BILLING_AUTHORIZATION_UNAVAILABLE` | The billing authority could not make a decision, so the platform failed closed | Stop the affected work and retry only after bounded backoff. A mid-stream realtime event is terminal and requires a new stream. |
| Realtime `409` / `ASR_STREAM_EXPIRED` | Audio inactivity or a lost backend sequence retired this ASR stream | Read `reason`, require `retry_scope: "new_stream"`, preserve committed output, and start a fresh UUID; never replay on the retired id. |
| Batch `429` / `RATE_LIMIT_EXCEEDED` | Explicit capacity backpressure | Queue or slow submissions, then use a bounded retry policy |
| HTTP `5xx` with `retryable: true` on a Batch result GET made with `save_result=true` | Preserved result read failed | Retry with capped backoff and jitter while the deadline remains |
| HTTP `5xx` with `retryable: true` on an upload | Server invites retry, but creation outcome can still be ambiguous | Don't blindly replay; apply an explicit duplicate-risk policy |
| Any response with `retryable: false` | Server says not to retry this request state | Stop until input, credentials, route, or configuration changes |
| Read timeout before any response | No platform classification | Retry only a read whose contract preserves the result, and only within the deadline |
| Realtime error or disconnect | Old stream state and accepted-audio boundary can be uncertain | Stop, preserve committed results, clean up, and recover with a fresh UUID if policy permits |
| TTS `voice_id` resolution error (SAU-2258) | A caller-supplied `voice_id` that is not a valid UUID is `400 VALIDATION_INVALID_UUID`; a well-formed one that does not identify an available voice is `400 TTS_VOICE_NOT_FOUND` (both non-retryable). A resolved voice with incomplete or corrupt stored data is a non-retryable `500 TTS_VOICE_RESOLUTION_FAILED`; a transient database/storage outage during resolution is a retryable `503 SERVER_DEPENDENCY_FAILURE`. Genuine model/capacity/inference failures stay a retryable `500 TTS_SYNTHESIS_FAILED` | Fix the `voice_id` or send `voice_references`; retry only the `503` and `500 TTS_SYNTHESIS_FAILED` with backoff, never the two non-retryable `400`s or `500 TTS_VOICE_RESOLUTION_FAILED` |
| TTS `400` after supplying both voice selectors, or a malformed reference | Supplying `voice_id` together with a non-empty `voice_references`, an explicit empty `voice_references` array, or reference audio that is not strictly canonical base64 mono PCM16 RIFF/WAVE, is a non-retryable validation error | For SDK calls, choose exactly one of `voice_id` or one canonical `voice_references` entry. Direct HTTP also permits neither selector, which uses deployment-defined voice selection. Never send both. |
A deployment gateway can return `429` for a Realtime HTTP request, while the
current Fast/live backend can collapse an internal audio-capacity failure into
retryable `500` with `ASR_TRANSCRIPTION_FAILED`. Do not infer a realtime quota,
capacity pool, or reset window from either response or from Batch capacity.
## 4. Treat Batch 429 as capacity backpressure
Batch `429` includes the normal structured fields plus `data.capacity`:
```json
{
"error": "error.rate_limit",
"code": "RATE_LIMIT_EXCEEDED",
"detail": "error.rate_limit",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z",
"data": { "capacity": 120.5 }
}
```
`capacity` is remaining capacity measured in audio seconds. Use it for queue
and admission decisions. It is not a documented quota, reset window, or number
of seconds to sleep.
The OpenAPI contract doesn't promise a `Retry-After` header. SDK
`retryAfter` / `retry_after` is populated only when a valid header is actually
present. If it is absent, apply capped exponential backoff with jitter. Always
bound attempts, individual delays, total retry time, and producer concurrency
with an overall deadline.
## 5. Preserve a Batch result before retrying its read
The released SDK doesn't retry batch calls. `maxRetries` / `max_retries` is
deprecated, ignored, and retained only for compatibility. These tested fixtures
retry `getResult()` / `get_result()`, not an upload, and explicitly pass
`saveResult: true` / `save_result=True`. The default `false` can clear a
terminal result after building the response, so a lost response can be followed
by `cleared`. The preservation option makes bounded retry possible but does not
define a retention duration. The fixtures use the released typed properties:
JavaScript / TypeScript
Python
```ts
import {
BatchTranscribeClient,
BatchTranscribeError,
BatchTranscribeRateLimitError,
Language,
type TranscriptionResponse,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function getResultWithRetry(
client: BatchTranscribeClient,
jobId: string,
attempts = 5,
): Promise {
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
// saveResult prevents a terminal read from clearing the stored result
// before a retry. It does not establish a retention duration.
return await client.getResult(jobId, Language.ArEn, { saveResult: true });
} catch (error: unknown) {
if (!(error instanceof BatchTranscribeError)) throw error;
const rateLimited = error instanceof BatchTranscribeRateLimitError;
const retryable = rateLimited || error.retryable === true;
console.error({
statusCode: error.statusCode,
code: error.code,
capacity: error.capacity,
});
if (!retryable || attempt === attempts) throw error;
const serverDelayMs = rateLimited && error.retryAfter !== undefined
? error.retryAfter * 1_000
: 0;
const exponentialDelayMs = 500 * 2 ** (attempt - 1);
await pause(Math.max(serverDelayMs, exponentialDelayMs) + Math.random() * 250);
}
}
throw new Error('Retry loop exhausted');
}
async function main(): Promise {
const jobId = process.argv[2];
if (!jobId) throw new Error('Pass a batch job ID as the first argument');
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
});
try {
const result = await getResultWithRetry(client, jobId);
console.info(result.status, result.results?.transcript ?? '');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import random
import sys
from humain_voice import stt
from humain_voice.stt.batchtranscription import TranscriptionResponse
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def get_result_with_retry(
client: stt.BatchTranscribeClient,
job_id: str,
attempts: int = 5,
) -> TranscriptionResponse:
for attempt in range(1, attempts + 1):
try:
# save_result prevents a terminal read from clearing the stored
# result before a retry. It does not define a retention duration.
return await client.get_result(
job_id, stt.Language.ArEn, save_result=True
)
except stt.BatchTranscribeError as error:
rate_limited = isinstance(error, stt.BatchTranscribeRateLimitError)
retryable = rate_limited or error.retryable is True
print(
{
"status_code": error.status_code,
"code": error.code,
"capacity": error.capacity,
}
)
if not retryable or attempt == attempts:
raise
server_delay = 0
if isinstance(error, stt.BatchTranscribeRateLimitError):
server_delay = error.retry_after or 0
exponential_delay = 0.5 * 2 ** (attempt - 1)
await asyncio.sleep(max(server_delay, exponential_delay) + random.random() * 0.25)
raise RuntimeError("Retry loop exhausted")
async def main() -> None:
if len(sys.argv) < 2:
raise RuntimeError("Pass a batch job ID as the first argument")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
) as client:
result = await get_result_with_retry(client, sys.argv[1])
print(result.status.value, result.results.transcript if result.results else "")
if __name__ == "__main__":
asyncio.run(main())
```
Expected behavior: retryable reads use at most five attempts, respect an actual
`retryAfter` / `retry_after` value when present, add exponential delay and
jitter, and rethrow the final failure. The attempt bound doesn't replace an
overall app deadline.
## 6. Keep ambiguous operations out of automatic retry
### Complete-file uploads
Batch job creation and fast complete-audio submission don't document an
idempotency-key contract. A timeout or disconnect after bytes were sent doesn't
prove either success or failure: the server may have accepted the request.
If a `jobId` or request UUID was returned, retain it and continue through that
operation's normal result path. Without a conclusive response, record the
ambiguous attempt and repeat only under an app policy that explicitly accepts
duplicate work.
### Realtime streams
The public Socket.IO and HTTP contracts define neither transparent resume nor
idempotent frame replay. On an error or disconnect:
1. Stop sending audio and close the old stream or response.
2. Preserve committed results and discard unresolved provisional state.
3. Record the uncertain audio interval.
4. Reconnect with bounded backoff and a fresh UUID only if the error and app
deadline permit it.
5. Keep the new stream separate until the app explicitly reconciles timelines.
Don't replay old frames or reuse the old UUID under an assumption of server-side
deduplication.
## 7. Separate timeouts from the overall deadline
| Control | What it bounds | What expiry proves |
|---------|----------------|--------------------|
| Connect or request timeout | One network phase or request | The client stopped waiting; not whether the server acted |
| Read or inactivity timeout | Time waiting for the next byte, chunk, or event | No progress arrived in that interval; not total operation duration |
| Realtime final-wait timeout | Wait after the final input frame | The wait ended; not that a final result arrived |
| Overall app deadline | Connection, work, retries, delays, and cleanup together | The app must stop further work |
JavaScript TTS `timeoutSeconds` defaults to 30 seconds of inactivity while
waiting for each audio chunk. Python TTS has no timeout unless
`timeout_seconds` is supplied. Realtime ASR SDK `close()` waits only for
protocol-level `is_final`, a routed error, or its close timeout and can return when
that wait expires. None of these controls replaces the overall deadline.
After any expiry, clean up in `finally`: cancel HTTP reads and close response
bodies; stop Socket.IO audio and call `disconnect()` or exit the Python async
context; close the batch client. Don't infer that client cleanup canceled
server-side work or in-flight TTS synthesis.
## 8. Log decisions and test the failure paths
Log the operation, transport, HTTP status or event name, `code`, retry decision,
request or job UUID, attempt, deadline remaining, timeout type, and Batch
capacity when present. Don't log API keys, full audio, or sensitive transcript
text by default.
Next, run the safe-read fixture, then test invalid input, authentication,
explicit `429`, read timeout, ambiguous upload timeout, realtime disconnect,
final-wait expiry, and cleanup in an isolated test environment.
---
# Direct API Overview
Locale: en
Source: https://docs.voice.humain.com/en/api-guides
Use these guides when your runtime has no released SDK, you need wire-level
control, or you need to diagnose transport behavior. JavaScript and Python apps
should normally start with the [SDK guides](/en/sdk).
## Choose by input lifecycle
| Input and outcome | Direct surface | Start with | Keep open as the contract |
|---|---|---|---|
| A meeting, podcast, archive, or other long-form complete recording that can finish asynchronously | **Batch REST**: upload once, receive `jobId`, and poll | [Batch REST guide](/en/api-guides/batch-rest) | [Batch OpenAPI](/en/api-reference/batch) |
| One complete latency-sensitive audio unit, such as a conversational turn | **Fast transcription**: send the whole unit through Socket.IO `audio_file` or HTTP multipart `/realtime/http/stt` | [Socket.IO guide](/en/api-guides/socketio) or [Realtime HTTP guide](/en/api-guides/realtime-http) | [Fast AsyncAPI](/en/api-guides/asyncapi/fast-transcription) or [Realtime HTTP OpenAPI](/en/api-reference/realtime-http) |
| Audio that's still arriving, with live text or speaker segments | **Realtime streaming**: Socket.IO `audio_stream` / `diarization_stream`, or framed HTTP streaming | [Realtime transport overview](/en/api-guides/realtime) | [Realtime AsyncAPI](/en/api-guides/asyncapi/realtime) and [Realtime HTTP OpenAPI](/en/api-reference/realtime-http) |
| Text that must become speech | **TTS**: Socket.IO `tts` / `tts_audio`, or direct HTTP TTS with its documented framing limitation | [Socket.IO guide](/en/api-guides/socketio); use [Realtime HTTP](/en/api-guides/realtime-http) only when your integration requires HTTP | [TTS AsyncAPI](/en/api-guides/asyncapi/tts) or [Realtime HTTP OpenAPI](/en/api-reference/realtime-http) |
Batch and fast transcription both consume complete audio. Choose batch for
long-form media and fast only for a bounded complete unit whose latency matters.
Result events don't make fast input realtime. Choose realtime only while audio
is still arriving.
## Shared prerequisites
- Obtain the environment-specific `API_URL` and `API_KEY` through the
[documented access flow](/en/authentication). The SDK defaults Socket.IO to
`/socket.io`; don't infer an override from another environment.
- Send `x-api-key` on every protected HTTP request and Socket.IO connection.
Keep it in a trusted backend; browser code can't keep an API key secret.
- Set finite connection, request, read, polling, and final-result deadlines.
Validate HTTP status before parsing success, and close every stream or socket.
| Surface | Required audio or output contract |
|---|---|
| Batch REST | One `multipart/form-data` file upload |
| Fast transcription | One complete encoded file in a Socket.IO packet or HTTP multipart request |
| Realtime ASR and diarization | PCM16 little-endian, 16 kHz, mono; each input body includes the documented 18-byte control header |
| Socket.IO TTS | Framed raw PCM16 little-endian, 24 kHz, mono; audio starts after the 17-byte frame header |
| HTTP TTS | Undelimited protocol capture whose conceptual frames carry 16 kHz PCM16; generic clients can't recover frame boundaries or playable audio |
## Guides and references answer different questions
| Use | When you need |
|---|---|
| **API guide** | A transport choice, request sequence, lifecycle rules, result reconciliation, cleanup, and operational cautions |
| **Generated OpenAPI reference** | Exact HTTP path, method, authentication, parameters, body, status codes, and response schemas |
| **Generated AsyncAPI reference** | Exact Socket.IO event names, payload fields, binary byte layouts, and connection security |
Read the guide first, then keep the matching generated reference beside your
implementation. If they appear to disagree on direct wire behavior, treat the
validated generated specification as the contract and report the guide drift.
## Next steps
1. [Verify the issued URL and key](/en/authentication) without uploading audio.
2. Choose one row in the preceding table and complete its smallest representative request.
3. Add structured error handling and bounded retry from
[Errors and Rate Limits](/en/api-guides/errors-and-rate-limits).
---
# Realtime HTTP
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/realtime-http
The `/realtime/http/*` operations are direct platform APIs. SDK `0.18.0`
doesn't wrap them. Use them only from a trusted runtime that can protect
`x-api-key`, enforce deadlines, and implement the validated OpenAPI framing.
## 1. Choose the operation by input lifecycle
| Input and outcome | Choose | Request unit | Completion signal |
|-------------------|--------|--------------|-------------------|
| A long or large complete meeting, podcast, or archive | [Batch REST](/en/api-guides/batch-rest), not a realtime HTTP operation | One complete file, then job polling | Batch `done`, `failed`, or `cleared` |
| One complete latency-sensitive conversational unit | `POST /realtime/http/stt` | One `multipart/form-data` file | NDJSON `STTResponse` with `is_final: true` |
| Audio still arriving when you need live text | `POST /realtime/http/stt-stream` | One 18-byte-header-plus-PCM body per request | An observed `is_speech_final` marks a speech boundary; only an observed `is_final` completes the stream |
| Audio still arriving when you need a speaker timeline | `POST /realtime/http/diarization-stream` | One framed PCM body per serialized request | An observed record with `is_final: true`; an active provisional tail can remain |
| Text must become speech | SDK Socket.IO TTS for playable output; direct HTTP only for a protocol capture | One JSON request | SDK completion; direct HTTP has no generically detectable frame boundary |
Fast transcription streams result lines, but its input is still one complete
file. It isn't a live microphone transport.
## 2. Prepare authentication, identifiers, and deadlines
- Obtain `API_KEY` through the [authentication flow](/en/authentication), and
use the `API_URL` rendered for this environment.
- Send `x-api-key` on every request from a trusted backend. Browser or mobile
code can't keep this credential secret. The key also needs the provisioned
capability: realtime ASR for Fast/live ASR, diarization for the speaker
stream, or TTS for synthesis.
- Generate a valid UUID for `id`. Fast STT carries it in the query, TTS carries
it in JSON, and live frames carry its 16 raw bytes. Reuse one UUID only for
the requests in the same live stream.
- Set a connect timeout, a finite timeout for each request and read, and an
overall operation deadline. Validate the HTTP status before parsing a
success stream.
- Buffer NDJSON across transport reads and split only on newline. One network
read can contain part of a line or several lines.
`API_PATH` applies to Socket.IO clients and isn't used by these HTTP routes.
## 3. Send one complete unit for fast transcription
Supply a UUID in `id` and one complete file in the multipart `file` field. Fast
applies only language and ASR model selection:
| Selector | Accepted values |
|----------|-----------------|
| `language` or `lang` | `en`, `ar`, `codeswitch`, `auto` |
| `asr` or `model` | Published model wire value |
A nonempty `language` takes precedence over `lang`; a nonempty `asr` takes
precedence over `model`. Omitted or `auto` language and an omitted model use
defaults configured for the environment. Use Batch when diarization, ITN, or
redaction is required.
```bash
export REQUEST_ID="7f51f2c2-e7bc-41c8-a850-f848df2ddfc8"
curl -N --fail-with-body --connect-timeout 10 --max-time 120 \
"${API_URL%/}/realtime/http/stt?id=$REQUEST_ID&language=codeswitch&asr=bayan_cs_ar_en" \
-H "x-api-key: $API_KEY" \
-F "file=@turn.wav"
```
HTTP `200` returns `application/x-ndjson`. Each non-empty line is one complete
JSON object; for example:
```json
{"id":"7f51f2c2-e7bc-41c8-a850-f848df2ddfc8","seq":0,"transcription":"hello wor","words":[{"start_time":0.0,"end_time":0.45,"word":"hello"}],"is_final":false}
{"id":"7f51f2c2-e7bc-41c8-a850-f848df2ddfc8","seq":0,"transcription":"hello world","words":[{"start_time":0.0,"end_time":0.45,"word":"hello"},{"start_time":0.46,"end_time":0.9,"word":"world"}],"is_final":true}
```
Process records in observed arrival order and retain `seq` only for diagnostics;
the current public Fast contract does not define ordering or uniqueness for it.
Treat `is_final: false` as provisional and finish the request state only after
`is_final: true`. Don't treat raw HTTP read chunks as records or assume that
every provisional transcription is append-only.
After partial output has started, a later failure ends the partial HTTP `200`
without appending an error JSON record. EOF, cancellation, or an application
deadline without `is_final: true` is incomplete and ambiguous; the operation
defines no replay contract, so do not blindly resubmit the audio.
## 4. Frame live ASR and diarization
Both live operations accept `application/octet-stream`. Every request body has
this layout:
Use one fresh nonzero UUID throughout. Set the start bit on the first request,
neither flag on intermediate requests, and the final bit on the last request;
set both for a one-chunk stream and keep reserved flag bits zero. Every request
must carry audio. A framed file such as `frame.bin` can be sent with
`--data-binary`; it isn't an audio file by itself because it includes the
18-byte control header.
### Build a valid frame
These tested builders default to a one-chunk stream, so both boundary flags are
set. For multiple chunks, reuse `STREAM_ID`, set `IS_FINAL=0` on the first
chunk, set both flags to `0` on intermediate chunks, and set only `IS_FINAL=1`
on the last chunk.
JavaScript / TypeScript
Python
```ts
import { randomUUID } from 'node:crypto';
import { readFile, writeFile } from 'node:fs/promises';
const languageBytes = {
ar: 0,
en: 1,
codeswitch: 2,
auto: 255,
} as const;
function uuidBytes(id: string): Uint8Array {
const hex = id.replaceAll('-', '');
if (!/^[0-9a-f]{32}$/i.test(hex) || /^0{32}$/.test(hex)) {
throw new Error('STREAM_ID must be a nonzero UUID');
}
return Uint8Array.from(hex.match(/.{2}/g)!, (byte) => Number.parseInt(byte, 16));
}
function frame(
id: string,
pcm16le: Uint8Array,
options: { language: keyof typeof languageBytes; isStart: boolean; isFinal: boolean },
): Uint8Array {
if (pcm16le.byteLength === 0 || pcm16le.byteLength % 2 !== 0) {
throw new Error('PCM16 payload must be nonempty and contain an even number of bytes');
}
const output = new Uint8Array(18 + pcm16le.byteLength);
output.set(uuidBytes(id), 0);
output[16] = (options.isStart ? 1 : 0) | (options.isFinal ? 2 : 0);
output[17] = languageBytes[options.language];
output.set(pcm16le, 18);
return output;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'chunk.pcm';
const outputPath = process.argv[3] ?? 'frame.bin';
const streamId = process.env.STREAM_ID ?? randomUUID();
const pcm = await readFile(inputPath);
// Defaults build a valid one-chunk stream. For a longer stream, reuse
// STREAM_ID and set only the boundary flags for each arriving PCM chunk.
const body = frame(streamId, pcm, {
language: 'codeswitch',
isStart: process.env.IS_START !== '0',
isFinal: process.env.IS_FINAL !== '0',
});
await writeFile(outputPath, body);
console.info({ streamId, bytes: body.byteLength, outputPath });
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import os
import sys
import uuid
from pathlib import Path
LANGUAGE_BYTES = {
"ar": 0,
"en": 1,
"codeswitch": 2,
"auto": 255,
}
def build_frame(
stream_id: uuid.UUID,
pcm16le: bytes,
*,
language: str,
is_start: bool,
is_final: bool,
) -> bytes:
if stream_id.int == 0:
raise ValueError("STREAM_ID must be a nonzero UUID")
if not pcm16le or len(pcm16le) % 2:
raise ValueError(
"PCM16 payload must be nonempty and contain an even number of bytes"
)
flags = (1 if is_start else 0) | (2 if is_final else 0)
return stream_id.bytes + bytes((flags, LANGUAGE_BYTES[language])) + pcm16le
def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "chunk.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "frame.bin")
stream_id = uuid.UUID(os.environ.get("STREAM_ID", str(uuid.uuid4())))
# Defaults build a valid one-chunk stream. For a longer stream, reuse
# STREAM_ID and set only the boundary flags for each arriving PCM chunk.
body = build_frame(
stream_id,
input_path.read_bytes(),
language="codeswitch",
is_start=os.environ.get("IS_START", "1") != "0",
is_final=os.environ.get("IS_FINAL", "1") != "0",
)
output_path.write_bytes(body)
print({"stream_id": str(stream_id), "bytes": len(body), "output": str(output_path)})
if __name__ == "__main__":
main()
```
### Live ASR
```bash
curl -N --fail-with-body --connect-timeout 10 --max-time 30 \
-X POST "${API_URL%/}/realtime/http/stt-stream" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/octet-stream" \
--data-binary @frame.bin
```
Send one POST per framed audio chunk. Each HTTP `200` contains zero or more
NDJSON records with `id`, `seq`, `transcription`, `words`, `is_speech_final`,
and `is_final`. A later failure ends a partial `200` without appending an error
record. Buffer across reads and parse complete lines. `is_speech_final` marks a detected
speech-segment boundary; only an observed `is_final: true` completes the whole
stream. The request final bit and an ending response, including an empty `200`,
do not. Treat `seq` as opaque and reconcile provisional text by `id` and
observed arrival order as described in the
[realtime lifecycle guide](/en/api-guides/realtime).
The public contract does not define whether chunk POSTs should overlap or be
serialized. Use only the coordination pattern provisioned for your environment;
do not infer routing safety from ordinary HTTP concurrency.
A normal non-final response window ends after two seconds and preserves the
session. Aborting a POST or timing out the final response cancels it. The
session expires after 60 seconds without accepted client audio or an inference
response.
`POST /realtime/http/realtime-asr` is a compatibility path. New clients should
use the canonical `POST /realtime/http/stt-stream` operation.
### Live diarization
```bash
curl -N --fail-with-body --connect-timeout 10 --max-time 30 \
-X POST "$API_URL/realtime/http/diarization-stream" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/octet-stream" \
--data-binary @frame.bin
```
This operation has no query parameters, multipart form, or client model
selector. The language byte must be `0`, `1`, `2`, or `255`, but the service
discards it after validation. Mark the last real audio frame final because an
empty terminator is invalid. A stream that never received a start frame returns
HTTP `400` with `VALIDATION_REQUIRED_FIELD`.
Keep at most one POST in flight for each stream UUID. Capture audio concurrently
into a bounded queue, but use one sender to drain it and close each response
before sending the next frame. Concurrent same-UUID requests can overwrite
response ownership; distinct UUID streams can run concurrently.
Each HTTP `200` contains zero or more NDJSON records with `id`,
`final_segments`, `active_segments`, and `is_final`. A later failure ends a
partial `200` without appending an error record. Accumulate unseen `final_segments` because each array
is a per-record delta. Replace the prior `active_segments` snapshot, then sort
the reconciled final-plus-active timeline by `start_time`. Speaker labels are
relative to one stream, not identities, and segment times are relative to its
start.
Only an observed `is_final: true` completes the stream. A final request bit,
empty `200`, EOF, or response deadline does not. A final record can retain a
nonempty active tail; preserve it as provisional instead of silently marking it
final. A normal non-final response window ends after two seconds and preserves
the session. Aborting a POST or timing out the final response cancels it, and
the session expires after 60 seconds without client or inference activity.
There is no chunk replay, resume, or idempotency contract. After an ambiguous
failure, close every response, mark the timeline incomplete, and recover with a
fresh UUID rather than replaying an old chunk.
## 5. Request HTTP TTS with its output contract in mind
The JSON body requires a fresh `id` and `text` containing at least one Unicode
letter or number after trimming. Optional fields are `model`, `voice_id`, and
`voice_references`. For a predictable voice, send one UUID `voice_id` or one
reference whose `audio` is standard-base64 RIFF/WAVE with non-empty mono PCM16
data and whose `text` is its transcript. The selectors are mutually exclusive.
Obtain `voice_id` through SDK `listVoices()` or `list_voices()`; there is no HTTP
voice-list operation. Set `model` to `nebula` explicitly instead of relying on
the deployment-configured default, which falls back to `nebula`.
```bash
curl --fail-with-body --connect-timeout 10 --max-time 120 \
-X POST "$API_URL/realtime/http/tts" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/json" \
--data '{"id":"7f51f2c2-e7bc-41c8-a850-f848df2ddfc8","text":"Hello from HUMAIN Voice","model":"nebula"}' \
--output tts-frames.bin
```
HTTP `200` returns a continuous `application/octet-stream` body:
The service appends a final frame even when that frame has no additional PCM.
The contract defines no frame-length field or delimiter. HTTP reader chunks are
transport chunks and aren't guaranteed to match service-frame boundaries, so a
generic client can't safely remove 17 bytes from every read. The example's
`tts-frames.bin` is a protocol capture, not a playable PCM or WAV file.
If synthesis fails after bytes were committed, the partial binary `200` stream
simply ends: no structured error JSON is appended. A missing boundary-aware final
flag, premature EOF, or deadline therefore leaves an incomplete capture with no
in-band explanation, and only a failure occurring before output was committed can
be reported as structured JSON. Aborting the HTTP request cancels its in-flight
synthesis. Direct HTTP model, capacity and inference failures are reported as retryable
`500 TTS_SYNTHESIS_FAILED`; a gateway can independently return `429`. A
content-policy rejection is non-retryable `400 TTS_INPUT_NOT_ALLOWED`; change
the text instead of resending it. If the moderation authority cannot decide,
synthesis fails closed with retryable `503 TTS_MODERATION_UNAVAILABLE`; do not
misreport that infrastructure failure as prohibited content. A caller-supplied
`voice_id` no longer collapses into `TTS_SYNTHESIS_FAILED` (SAU-2258): an
unparseable `voice_id` is `400 VALIDATION_INVALID_UUID` and a well-formed one that
does not identify an available voice is `400 TTS_VOICE_NOT_FOUND` (both
non-retryable); a resolved voice whose stored data is incomplete or corrupt is
`500 TTS_VOICE_RESOLUTION_FAILED` (non-retryable); and a transient
database/storage outage during voice resolution is `503 SERVER_DEPENDENCY_FAILURE`
(retryable).
Text and voice-reference problems no longer collapse that way. Over-limit text,
an over-limit reference transcript, more than one reference, and a reference clip
longer than the deployment's configured reference ceiling are non-retryable
`422`; a reference
whose decoded size is over the ceiling is `413`; and a malformed reference,
supplying both voice selectors, or an explicit empty `voice_references` array are
non-retryable `400`. All are checked before any model lookup, admission or
charge, and each limit rejection carries a `data` object naming the bound, its
configured value and the observed value. See
[Errors and rate limits](/en/api-guides/errors-and-rate-limits).
Until your direct client has an unambiguous frame-boundary mechanism, use SDK
Socket.IO TTS and the [TTS-to-WAV recipe](/en/recipes/text-to-speech-to-file)
for playable output. Don't assume the Socket.IO 24 kHz output format for this
16 kHz HTTP operation.
## 6. Bound failures and clean up every stream
1. Validate the HTTP status before selecting the NDJSON or binary success
parser. A deployment gateway can return `429`; current backends can instead
collapse capacity failures into retryable `500` with
`ASR_TRANSCRIPTION_FAILED`, `DIARIZATION_FAILED`, or
`TTS_SYNTHESIS_FAILED`. Treat each layer's actual status and body as evidence,
and do not infer a numeric quota or reset window.
2. For `ErrorResponse`, branch on `code` and `retryable`, not the wording of
`error`, `detail`, or `message`.
3. On a live-stream failure or deadline, stop sending frames, abort the request,
close its response reader, and start recovery with a fresh UUID. Session
resume after interruption isn't documented.
4. A timeout after sending the complete multipart file is ambiguous. The
contract doesn't define idempotent replay, so don't repeat it blindly.
5. If a boundary-aware TTS client ends without a final frame, keep partial
bytes separate from complete output and close the response. Don't infer
completion from connection close alone.
Apply bounded retry only when the structured error permits it, the operation is
safe under your application policy, and the overall deadline remains. See
[Errors and Rate Limits](/en/api-guides/errors-and-rate-limits).
## 7. Continue with the contract and production checks
Start with the smallest representative request for the chosen operation and
verify its documented final signal. Keep the generated OpenAPI reference beside
your implementation for exact parameters, schemas, and errors, then exercise
deadlines, malformed frames, disconnects, and cleanup before launch.
---
# Realtime Overview
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/realtime
Realtime means the audio is still arriving when transcription or diarization
begins. A streamed response doesn't make a complete uploaded file realtime.
## 1. Choose by source lifecycle
| Source state when processing starts | Choose | Contract |
|-------------------------------------|--------|----------|
| A long or large complete meeting, podcast, or archive | [Batch REST](/en/api-guides/batch-rest) | Upload once, receive `jobId`, and poll a job |
| One complete latency-sensitive conversational unit | Fast transcription through Socket.IO `audio_file` or HTTP `POST /realtime/http/stt` | Send the whole unit; finish on `is_final: true` |
| Audio still arriving from a microphone, call, or live source | Realtime ASR or diarization | Send framed PCM as it arrives; reconcile provisional and final state |
TTS can stream generated output, but it isn't the live audio-input lifecycle
defined here. See the concrete transport guides for TTS behavior.
## 2. Choose the live transport
| Concern | Socket.IO with SDK `0.18.0` | Direct framed HTTP |
|---------|------------------------------|--------------------|
| Released wrapper | JavaScript and Python | None |
| Configuration | `API_URL` and `API_KEY`; SDK defaults to `/socket.io` | `API_URL` and `API_KEY`; no Socket.IO path |
| Live ASR input | SDK stream sends `audio_stream` | One `POST /realtime/http/stt-stream` per framed chunk |
| Live diarization input | SDK stream sends `diarization_stream` | One `POST /realtime/http/diarization-stream` per framed chunk |
| Results | `transcription_result` and `diarization_result` events | `application/x-ndjson` response records |
| Framing owner | SDK creates and routes frames by UUID | App creates every 18-byte header and reuses the UUID |
| Cleanup owner | Close the stream, then disconnect the client | Send a final frame, finish or stop reads, and close response bodies |
Use the SDK transport when the runtime supports Socket.IO. Use direct HTTP when
the trusted runtime can't use Socket.IO and can implement the exact framing and
response contract itself.
Both live transports require `x-api-key` and PCM16 little-endian, 16 kHz, mono
audio. Start them from a trusted backend. Each input frame contains 16 raw UUID
bytes, a flags byte, a language byte, then PCM. The concrete transport guides
below show the exact layout.
## 3. Create one state record per stream
Before sending audio, create a fresh UUID and one app-owned state record for
that stream. Track:
- the stream `id` and an app-assigned arrival counter;
- one replaceable provisional transcription;
- committed final-event words in observed arrival order;
- whether speech-final and stream-final signals arrived;
- closed and active diarization segments; and
- the first structured error plus the overall deadline.
Keep this state independent from the socket or HTTP reader. A transport close
must not erase committed text, and a late provisional response must not replace
newer or finalized state.
## 4. Reconcile ASR arrival order and finality
The response contains `seq`, but the current public Realtime contract does not
define ordering or uniqueness semantics for it. Assign a local arrival number,
check both final flags on every response, and apply these mutations:
| Signal | Meaning | State action |
|--------|---------|--------------|
| Result event arrives | New observed state | Record a local arrival number; keep the server `seq` only as diagnostic data |
| `is_final: false` and `is_speech_final: false` | Provisional text | Replace the current provisional display |
| `is_speech_final: true` | The model detected an end-of-speech boundary | Commit that event's words in arrival order, then clear the provisional value it supersedes while the stream may continue |
| `is_final: true` | Final result for the transcription stream | Commit that event once, clear superseded provisional text, and mark the stream result terminal |
When both final flags are true on one response, commit it once and record both
facts. Never infer either flag from a quiet interval, a closed connection, or a
completed `close()` call.
Build `SRT` or `WebVTT` only from finalized word timing. `RealtimeSubtitles`
deduplicates by `id:seq`, so it can collapse distinct final events while the
server supplies non-distinct `seq` values. For this contract, collect final
words in observed arrival order and render them with `Subtitles`.
## 5. Reconcile diarization as an evolving timeline
For each `diarization_result` or HTTP diarization record:
1. Preserve and deduplicate `final_segments`; these closed segments don't
change.
2. Replace the prior `active_segments` collection with the latest one; these
segments can evolve or become final.
3. Treat `is_final: true` as the last response for that diarization stream.
4. Reconcile the latest speaker timeline with finalized word timing using an
explicit overlap rule.
Speaker labels represent relative turns in this stream, not real-world
identity.
## 6. End with separate deadlines and explicit cleanup
Use separate finite deadlines for connection, the whole session, each send or
read, and the final-result wait. Then end the stream in this order:
1. Stop the audio producer so it can't enqueue more PCM.
2. Send exactly one documented final frame.
3. Wait only until the final-result deadline for the relevant final signal.
4. Record whether termination was complete, timed out, or failed.
5. Release the transport in a `finally` block or async context.
For realtime ASR in SDK `0.18.0`, JavaScript
`stream.close(timeoutSeconds)` and Python
`stream.close(timeout_seconds=...)` send the final frame and wait for
protocol-level `is_final`, a routed error, or the supplied timeout. They return
when the wait expires instead of raising a timeout error. That return isn't
proof that `is_final` arrived; inspect the state recorded by the callbacks.
`is_speech_final` is only an utterance boundary and does not release the close
wait. The diarization helper likewise returns its best-known timeline if the
final wait expires.
After stream-level termination, JavaScript must still call `disconnect()` in
`finally`. Python must still exit the client async context. For direct HTTP,
cancel an expired request, and close its response reader.
## 7. Treat disconnect outcome as ambiguous
The public contracts define neither session resumption nor idempotent audio
frame replay. They don't guarantee what server-side state survives a dropped
Socket.IO connection or interrupted HTTP request. Recover across a new stream
boundary:
1. Stop feeding the old stream and close its transport.
2. Preserve committed results, discard unresolved provisional text, and mark
the uncertain audio interval.
3. Retry only if the structured error and app policy allow it and the overall
deadline remains. Bound backoff, jitter, attempts, and elapsed time.
4. Reconnect with a fresh UUID and send a new start frame.
5. Keep the new stream's results separate until the app explicitly joins the
two committed timelines.
Don't reuse the old UUID or replay frames under an assumption of server-side
deduplication. If the app retained audio from the uncertain interval,
process it through an explicit recovery path instead of silently splicing it
into the new live stream. See
[Errors and Rate Limits](/en/api-guides/errors-and-rate-limits).
## 8. Continue with a transport, reference, and recipe
Choose one transport, run its smallest representative live stream, verify the
right final signal, and exercise timeout and disconnect paths before production.
---
# Socket.IO API
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/socketio
Use this guide for the Socket.IO lifecycle: choose a capability, connect,
register the minimum events, recognize its final signal, and always disconnect.
Use the generated AsyncAPI pages for complete payload schemas.
For JavaScript and Python applications, prefer SDK `0.18.0`; it builds binary
frames, routes UUIDs, normalizes errors, and provides close helpers. Build a
direct client only when you need wire-level control.
## Choose a workflow
| Input you have | Choose | Completion signal |
|---|---|---|
| A short, complete, latency-sensitive audio unit such as one conversational turn for a voice agent | Fast transcription | `transcription_result.is_final === true` |
| PCM audio that is still arriving and needs text | Realtime ASR | Wire terminal: `is_final === true`; speech boundary: `is_speech_final === true` |
| PCM audio that is still arriving and needs speaker turns | Live diarization | Final input frame, then `diarization_result.is_final === true` or an app deadline |
| Text that needs generated speech | Voice discovery, then TTS | Final bit in a `tts_audio` frame |
Fast transcription receives the complete payload once. It isn't the path for
long-form meetings, podcasts, or archive media; use batch transcription for
those complete recordings.
## Connection prerequisites
- The `API_URL` and `API_KEY` issued for the environment. Direct Socket.IO
clients also set the path to `/socket.io`.
- A server-side Socket.IO client. Keep `API_KEY` out of browser and mobile
bundles.
- Set `transports: ["websocket"]` for the published, portable transport
contract. Some deployments may route polling, but clients must not depend on it.
- Send `x-api-key` and `Origin` as connection headers. The production edge
runs a web app firewall that rejects a handshake without `Origin`; set it to
the scheme and host of `API_URL`.
- Event handlers registered before the connection or before sending a request.
- An overall app deadline for every request or stream.
Direct Socket.IO clients keep the path explicit. SDK `0.18.0` defaults to
`/socket.io`; pass `api_path` only when a self-hosted deployment or one behind a proxy
uses an override. The legacy `sautech.humain.com` endpoint requires
`/realtime/socket.io`.
## Connect once and disconnect
One connection can multiplex multiple requests or streams. Give each one a UUID
and route every response by `id` before processing it.
JavaScript / TypeScript
Python
```ts
import { io } from "socket.io-client";
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!,
},
});
try {
// Register handlers, wait for connect, and run one or more operations.
} finally {
socket.disconnect();
}
```
```python
import asyncio
import os
import socketio
API_URL = os.environ["API_URL"]
API_KEY = os.environ["API_KEY"]
async def main() -> None:
sio = socketio.AsyncClient()
try:
await sio.connect(
API_URL,
headers={"x-api-key": API_KEY, "Origin": API_URL},
socketio_path=os.environ.get("API_PATH", "/socket.io"),
transports=["websocket"],
)
# Register handlers before connect in real code, then run operations.
finally:
if sio.connected:
await sio.disconnect()
asyncio.run(main())
```
**Expected:** the client emits its connection-success callback before any
application request is sent. Treat connection failure as terminal for that
attempt and clean up before retrying.
In `python-socketio`, `transports` is a `connect()` argument, not an
`AsyncClient` constructor argument.
## Fast transcription of a complete audio unit
Fast transcription accepts one complete AAC, FLAC, MP3, MP4, or WAV payload.
An MP4 must have its `moov` atom at the front. Send raw binary, not JSON or
base64.
Minimal sequence:
1. Register `audio_file_upload_success`, `transcription_result`, and `error`.
2. Emit one `audio_file` binary packet.
3. Match `audio_file_upload_success.id` to the request UUID; this acknowledges
receipt, not transcription completion.
4. Route result events by `id`, and treat their `seq` as opaque because the
public Fast contract does not define ordering or aggregation semantics.
Finish only when `is_final` is true.
5. Keep or reuse the connection only under an app deadline; otherwise
disconnect.
The `audio_file` packet has this exact variable-length layout:
| Offset | Size | Field |
|---|---:|---|
| `0..15` | 16 bytes | Request UUID |
| `16` | 1 byte | Language: `0` Arabic, `1` English, `2` codeswitch, `255` auto |
| `17..18` | 2 bytes | `asr_model_key` byte length, unsigned 16-bit little-endian |
| next `N` | `N` bytes | UTF-8 `asr_model_key`; zero length selects the language default |
| next 2 | 2 bytes | `dia_model_key` byte length, unsigned 16-bit little-endian |
| next `N` | `N` bytes | Reserved `dia_model_key`; send zero length |
| next 2 + `N` | variable | Reserved `itn_model_key`; send zero length |
| next 2 + `N` | variable | Reserved `redact_model_key`; send zero length |
| remaining | variable | Complete encoded audio-file bytes |
SDK `0.18.0` serializes the three reserved compatibility fields, but the
validated public Fast service does not apply them. Use Batch when diarization,
ITN, or redaction is required.
JavaScript SDK `0.18.0` has no fast-transcription timeout option. A routed
request error calls `onError` and then rejects with a generic message-only
`Error`. Don't blindly resend an ambiguous upload; there is no published
idempotency-key contract.
## Realtime ASR framing and lifecycle
`audio_stream` carries PCM16 little-endian, 16 kHz, mono samples. Reuse one UUID
for the whole stream.
Minimal sequence:
1. Register `transcription_result`, optional `diarization_result`, and `error`.
2. Emit exactly one start frame with flags byte `1`.
3. Emit intermediate frames with flags byte `0`.
4. Emit exactly one final frame with flags byte `2`.
5. Route text by `id` and observed arrival order. Keep server `seq` for
diagnostics only because its ordering and uniqueness are not public
guarantees. Replace provisional text while both final flags are false;
commit the event's words once when `is_final` or `is_speech_final` is true.
6. After the final input, a direct client waits for `is_final: true` until the
app deadline. The released SDK `close()` helper waits for the same
protocol-level `is_final`, a routed error, or its bounded timeout.
`is_speech_final` does not release that wait. Inspect the response state;
a successful return can be a timeout and does not itself prove finality.
The tested SDK recipe sends 3,200 audio bytes, or 100 ms, per frame. This is a
practical cadence, not a throughput or latency guarantee. Set flags byte bit 2
only when you also want `diarization_result` events on the same connection.
## Live diarization framing and lifecycle
`diarization_stream` uses the same 18-byte frame layout and required PCM format
as `audio_stream`. Its flags use bit 0 for start and bit 1 for final; keep other
bits zero.
Minimal sequence:
1. Register `diarization_result` and `error`.
2. Send one start frame, intermediate frames, and one final frame under the
same UUID.
3. Accumulate unseen `final_segments` additions and replace the current
`active_segments` tail on every result.
4. Treat `is_final: true` as the final server signal. If the deadline expires
first, return the best-known reconciled timeline as incomplete.
5. Disconnect in cleanup.
The released SDK helper recommends 15,360 audio bytes per feed. Consume results
while sending; deferring consumption until after the feed can stall the
workflow. SDK `close(5)` returns the best-known timeline when its final wait
expires.
## Voice discovery and TTS lifecycle
Discover a voice instead of guessing an ID:
1. Register `tts_voice_list_result` and `error`.
2. Emit `tts_voice_list` with `{}`.
3. Treat the response as an array of `{ id, label }`; handle an empty array.
Then synthesize:
1. Register `tts_audio` and `error`.
2. Emit `tts` with `id`, `text` containing a Unicode letter or number after
trimming, and explicit `model: "nebula"`.
3. For predictable voice selection, send either `voice_id` from discovery or
one `voice_references` item shaped `{ audio, text }`. Its `audio` is
standard-base64 RIFF/WAVE with non-empty mono PCM16 data. The selectors are
mutually exclusive.
4. Match every binary response by the request UUID, append bytes `17..end`, and
stop when byte `16` bit 0 is set.
The final bit is the TTS completion signal. Parse every `tts_audio` event with
this application header and never append its first 17 bytes. Use the
[tested TTS-to-WAV recipe](/en/recipes/text-to-speech-to-file) to create a
playable file. Disconnecting cancels the active synthesis requests owned by
that connection and suppresses their later audio and error events; it does not
close inference connections shared with other requests.
## Structured errors, deadlines, and termination
The generated event contracts define `error` objects with required `code`,
`message`, `retryable`, and `timestamp`, plus request `id` when the payload can
be routed. Register both request-scoped and global error handling.
| Capability | Final signal | Deadline and cleanup rule |
|---|---|---|
| Fast transcription | `is_final: true` | No JavaScript SDK timeout; bound the whole request and close the client |
| Realtime ASR | Wire terminal and SDK close signal: `is_final: true` | A resolved SDK close can mean its timeout expired; inspect tracked finality and always disconnect in `finally` |
| Live diarization | Final input frame, then `is_final: true` | On close timeout, keep the best-known timeline and mark it incomplete |
| Voice discovery | One `tts_voice_list_result`, which can be empty | Bound the wait; don't invent a voice ID |
| TTS | `tts_audio` header bit 0 set | SDK timeouts are client controls; the server also enforces a non-resetting 25-second overall deadline and a 60-second inactivity watchdog. Disconnect cancels this connection's active requests. |
SDK `0.18.0` normalizes structured callbacks. A legacy non-object payload becomes
`{ message }`. Fast and TTS request promises reject with generic message-only
errors after their structured callbacks. A timeout doesn't prove finality: stop
sending, preserve confirmed results, record incomplete termination, and
disconnect.
Use `retryable` as one input to a bounded retry policy, not as permission for an
unlimited retry. Never replay an upload whose outcome is ambiguous without an
application duplication policy.
## Generated event reference
This guide intentionally stops at lifecycle and framing. The generated AsyncAPI
pages contain every field, required property, example, and schema constraint.
---
# Recipes Overview
Locale: en
Source: https://docs.voice.humain.com/en/recipes
Recipes begin after setup and end with a usable artifact or finalized state.
Choose by what your app has as input—not by which transport sounds
familiar.
## Before you begin
- Use JavaScript or Python SDK `0.18.0` and complete the
[Quickstart](/en/quickstart) unless you already made a tested request.
- Have the current `API_URL` and `API_KEY`; Socket.IO defaults to `/socket.io`.
Keep the key in a trusted server environment.
- Use representative audio or text and choose a destination for the completed
artifact before running the recipe.
CI compiles or type-checks every displayed JavaScript and Python program from
the same fixture against SDK `0.18.0`.
## Choose by input
## Where fast transcription fits
Fast transcription is a separate SDK path for a **complete audio unit whose
latency matters**, such as one conversational turn. It sends the whole encoded
unit and then receives result events. It's not live microphone streaming, and
this documentation doesn't route meetings, podcasts, archives,
or other long-form media through it—use the batch recipe for those.
Start from the [SDK guide](/en/sdk) when fast transcription matches the input.
## Next steps
A completed recipe establishes its stated artifact and cleanup path. Before
launch, repeat it with representative inputs and exercise deadlines, terminal
states, disconnects, retries, capacity backpressure, empty voice lists, and
secret handling.
---
# Transcribe Live Audio
Locale: en
Source: https://docs.voice.humain.com/en/recipes/realtime-transcription
This recipe builds one production-shaped live transcription session. It starts
while audio is still arriving, keeps provisional UI state separate from
committed text, writes captions from finalized words, and closes every resource
at a defined boundary.
## When to use this recipe
Choose by the state of the audio:
| Audio state | Use | Typical input |
|---|---|---|
| Still arriving | `RealtimeClient` (this recipe) | Microphone, call, or another live source |
| Complete, bounded, and latency-sensitive | `FastTranscriptionClient` | One complete conversational turn for an AI agent |
| Complete and long-form | `BatchTranscribeClient` | Meeting, interview, podcast, or archive recording |
Fast transcription receives a complete audio unit. Batch owns complete
long-form recordings. Neither replaces Realtime ASR when the producer must send
audio before the utterance has ended.
## Before you start
You need:
- JavaScript `@humain-voice/sdk@0.18.0` or Python
`humain-voice==0.18.0` in a trusted server runtime.
- The provisioned `API_URL` and `API_KEY`. Both released `RealtimeClient`
implementations default to `/socket.io`.
- A source that can provide raw PCM16 little-endian, 16 kHz, mono audio.
- An app-level session deadline and a place to keep provisional, committed, and
error state separately.
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
Keep the API key out of browser and mobile code. See
[Authentication](/en/authentication) for the organization's credential flow.
## 1. Prepare raw PCM input
The Realtime ASR audio contract is exact:
| Property | Required value |
|---|---|
| Encoding | Signed PCM16 little-endian |
| Sample rate | 16,000 Hz |
| Channels | Mono |
| Tested fixture pacing | 3,200 bytes every 100 ms |
For a repeatable walkthrough, convert a recording to the same raw format that a
microphone or call pipeline must produce:
```bash
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ar 16000 -ac 1 speech.pcm
```
Send the raw bytes, not a WAV header or compressed container. The 3,200-byte
chunk and 100 ms pace are the tested fixture's framing choice; the input format
is the service contract.
## 2. Run the tested happy path
The programs read `speech.pcm`, pace it like a live producer, label every
response, collect final-event words in arrival order, wait up to five seconds
for final state, render `speech.vtt` with `Subtitles`, and clean up the client.
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
type ErrorResponse,
Language,
RealtimeClient,
Subtitles,
type WordSegment,
} from '@humain-voice/sdk';
const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'speech.pcm';
const outputPath = process.argv[3] ?? 'speech.vtt';
const client = new RealtimeClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
const finalizedWords: WordSegment[] = [];
let serverError: ErrorResponse | undefined;
let protocolFinalObserved = false;
try {
const stream = await client.startStream(Language.ArEn, {
onResponse: (response) => {
const kind = response.is_final
? 'final'
: response.is_speech_final
? 'speech-final'
: 'partial';
console.info(`${kind}:`, response.transcription);
if (response.is_final) protocolFinalObserved = true;
if (response.is_final || response.is_speech_final) {
// The current public Realtime contract does not guarantee increasing
// seq values, so collect final words in arrival order instead of
// asking RealtimeSubtitles to deduplicate by id:seq.
finalizedWords.push(...response.words);
}
},
// The released SDK can invoke a stream handler more than once for one
// routed error, so keep this callback idempotent.
onError: (error) => {
serverError = error;
},
});
const pcm = await readFile(inputPath);
for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
await pause(100);
}
// close() sends the last frame and waits for protocol is_final, a routed
// error, or this timeout. It resolves rather than throwing on timeout.
await stream.close(5);
if (serverError) {
throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
}
if (!protocolFinalObserved) {
throw new Error('Realtime stream ended before protocol is_final');
}
await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
CHUNK_BYTES = 3_200 # 100 ms of PCM16LE, 16 kHz, mono audio.
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "speech.vtt")
finalized_words: list[stt.WordSegment] = []
server_error: stt.ErrorResponse | None = None
protocol_final_observed = False
def handle_response(response: stt.RtTranscribeResponse) -> None:
nonlocal protocol_final_observed
if response.is_final:
kind = "final"
elif response.is_speech_final:
kind = "speech-final"
else:
kind = "partial"
print(f"{kind}:", response.transcription)
if response.is_final:
protocol_final_observed = True
if response.is_final or response.is_speech_final:
# The current public Realtime contract does not guarantee increasing
# seq values, so collect final words in arrival order instead of
# asking RealtimeSubtitles to deduplicate by id:seq.
finalized_words.extend(response.words)
def handle_error(error: stt.ErrorResponse | None) -> None:
# The released SDK can invoke a stream handler more than once for one
# routed error, so keep this callback idempotent.
nonlocal server_error
server_error = error
client = stt.RealtimeClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
stream = await client.start_stream(
language=stt.Language.ArEn,
on_response=handle_response,
on_error=handle_error,
)
pcm = input_path.read_bytes()
for offset in range(0, len(pcm), CHUNK_BYTES):
await stream.send(pcm[offset : offset + CHUNK_BYTES])
await asyncio.sleep(0.1)
# close() sends the last frame and waits for protocol is_final, a routed
# error, or this timeout. It returns rather than raising on timeout.
await stream.close(timeout_seconds=5.0)
if server_error is not None:
raise RuntimeError(server_error.message or server_error.code or "Realtime stream failed")
if not protocol_final_observed:
raise RuntimeError("Realtime stream ended before protocol is_final")
output_path.write_text(
stt.Subtitles.from_words(finalized_words).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
A successful run has these observable outcomes:
1. Each response is printed as `partial`, `final`, or `speech-final` according
to its flags.
2. No recorded server error remains when the stream finishes.
3. `speech.vtt` contains cues built only from finalized word timing.
4. The JavaScript client disconnects in `finally`; the Python async context
closes its Socket.IO and underlying HTTP resources.
The saved PCM file makes the walkthrough repeatable. In production, replace the
file read and timer with the microphone or call source, while keeping the same
state, termination, and cleanup boundaries.
## 3. Reconcile provisional and final text
Realtime text is evolving state, not one append-only string. Route responses by
stream `id`, assign an app-local arrival number, and apply this transition
table. Keep server `seq` only as diagnostic data because its ordering and
uniqueness are not part of the current public contract.
| Signal | State | UI and storage action |
|---|---|---|
| `is_final=false`, `is_speech_final=false` | Provisional | Replace the current provisional display for that stream; do not append it to the committed transcript. |
| `is_final=true` (with either `is_speech_final` value) | Final result | Commit that event once in observed arrival order, then remove the provisional value it supersedes. |
| `is_final=false`, `is_speech_final=true` | Speech-final result | Commit that event's words in arrival order, clear superseded provisional text, and record the speech boundary. |
| Routed `onError` / `on_error` | Failed stream | Record the structured error once, stop feeding audio, and begin cleanup. |
Keep the error callback idempotent. SDK `0.18.0` can invoke a stream error
handler more than once for one routed error.
Do not render a late provisional response over committed text. Preserve the
last committed transcript independently from the mutable provisional line so a
disconnect cannot erase stable results.
## 4. Generate captions from finalized words
In the response callback, ignore words while both final flags are false. Append
the words from final or speech-final events to an app-owned array in observed
arrival order. After termination, pass that array to `Subtitles.fromWords()` /
`Subtitles.from_words()` and render WebVTT.
SDK `0.18.0` also exposes `RealtimeSubtitles`, which ignores provisional events
and deduplicates final events by `id:seq`. Do not use it to collect multiple
final events against the current wire contract, because distinct `seq` values
are not guaranteed. The fixtures use the app-owned collection path and write
the caption file only after the stream closes and recorded errors are checked.
## 5. Terminate on a deadline and clean up
When the producer has no more audio, call `close(5)` in JavaScript or
`close(timeout_seconds=5.0)` in Python. In release `0.18.0`, close:
1. sends the final stream frame;
2. waits for protocol-level `is_final`, a routed error, or the supplied timeout; and
3. resolves when the wait expires instead of raising a timeout error.
The SDK default final-result wait is one second; the fixtures deliberately pass
five. This timeout bounds only the close wait. Keep a separate app deadline for
connection, audio production, sending, and the complete session.
A resolved close does not prove `is_final` arrived. `is_speech_final` is an
utterance boundary and does not release the close wait. Check the protocol-final
and error state recorded by callbacks. If the stream must be abandoned,
`stop()` / `stop_sync()` removes its context without the final wait.
Always perform client-level cleanup after stream-level termination. A routed
error can remove the stream context before close runs, but JavaScript must still
call `disconnect()` in `finally`, and Python must still exit the client context.
## 6. Recover only across a new stream boundary
The public contract does not define transparent session resume or what server
state survives a dropped connection. On a routed error or disconnect:
1. Stop feeding the old stream and preserve only committed final results.
2. Discard unresolved provisional text and clean up the old client.
3. If the app deadline and retry policy allow, reconnect with bounded backoff
and jitter and create a new stream with a fresh ID.
4. Keep the new stream's results separate until the app explicitly joins the
two committed timelines.
Do not assume that replaying earlier chunks is safe; the contract provides no
resume position or per-chunk acknowledgement. Audio captured around the drop
may need to be retained and processed separately. See the
[Realtime lifecycle guide](/en/api-guides/realtime) for the full recovery
boundary.
## Next steps
---
# Generate a Playable WAV File
Locale: en
Source: https://docs.voice.humain.com/en/recipes/text-to-speech-to-file
This recipe turns one text input containing a Unicode letter or number after
trimming into a complete file for a media player. It discovers a voice at
runtime, stops safely when none is returned,
waits for final audio, writes the correct PCM metadata, and closes the client on
every path.
## When to use this recipe
Use the buffered workflow when the app needs a complete WAV artifact before it
publishes, stores, or plays the result. If playback or processing must begin
before synthesis finishes, use the streaming method described below and keep
the same final-chunk, container, timeout, error, and cleanup boundaries.
This recipe covers Socket.IO TTS through the released JavaScript and Python
SDKs. It does not define the output contract for a different transport.
## Before you start
| Requirement | `0.18.0` contract |
|---|---|
| SDK | `@humain-voice/sdk@0.18.0` or `humain-voice==0.18.0` in a trusted server runtime |
| Connection | Provisioned `API_URL` and `API_KEY`; SDK defaults to `/socket.io` |
| Text | After trimming, contains at least one Unicode letter or number; whitespace-only and punctuation-only input is invalid |
| Voice input | Exactly one of `voice_id` or a non-empty `voice_references` collection |
| Output | A writable destination for the final WAV artifact |
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
The tested path discovers a `voice_id`; it does not assume that a particular
voice or any voice is available. Keep the API key in the trusted runtime; the
SDK uses `/socket.io` by default.
If the app uses `voice_references` instead, send one reference whose audio is
standard-base64 RIFF/WAVE containing non-empty mono PCM16 data.
## 1. Discover a voice
Call `listVoices()` / `list_voices()` before synthesis when the app has not
already been given a supported voice reference.
| Runtime | Released default | This recipe |
|---|---|---|
| JavaScript | `listVoices()` defaults to 5 seconds | Passes `timeoutSeconds: 5` explicitly |
| Python | `list_voices()` has no timeout unless supplied | Passes `timeout_seconds=5.0` |
The result contains seven multilingual `{ id, label, profile }` entries when
all configured variants are available. Treat the list as runtime data:
1. If the list is empty, stop this `voice_id` workflow before indexing it.
2. If a request fails, preserve its structured error state and clean up.
3. If a voice is returned, pass its exact `id`; do not derive an ID from the
label.
Passing a profile ID lets Platform select its physical variant from the text.
For current Arabic/English profiles, any Arabic-script letter selects Arabic;
otherwise English is selected. Physical variant IDs are internal and rejected.
An empty list is an operational result, not a promise about future voice
availability. Do not invent a fallback voice ID.
## 2. Run the tested happy path
The programs request voices, reject an empty list, select `TtsModel.Nebula`,
synthesize the text `Hello from HUMAIN Voice`, derive the model sample rate,
write `speech.wav`, and close the client.
JavaScript / TypeScript
Python
```ts
import { writeFile } from 'node:fs/promises';
import {
TTSClient,
TtsModel,
getSampleRate,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
function pcm16ToWav(pcm: Uint8Array, sampleRate: number): Buffer {
const header = Buffer.alloc(44);
header.write('RIFF', 0);
header.writeUInt32LE(36 + pcm.byteLength, 4);
header.write('WAVE', 8);
header.write('fmt ', 12);
header.writeUInt32LE(16, 16);
header.writeUInt16LE(1, 20); // Linear PCM.
header.writeUInt16LE(1, 22); // Mono.
header.writeUInt32LE(sampleRate, 24);
header.writeUInt32LE(sampleRate * 2, 28);
header.writeUInt16LE(2, 32);
header.writeUInt16LE(16, 34);
header.write('data', 36);
header.writeUInt32LE(pcm.byteLength, 40);
return Buffer.concat([
header,
Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength),
]);
}
async function main(): Promise {
const outputPath = process.argv[2] ?? 'speech.wav';
const client = new TTSClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
const voices = await client.listVoices({ timeoutSeconds: 5 });
const voice = voices.find((candidate) => candidate.profile) ?? voices[0];
if (!voice) throw new Error('No TTS voices are available');
if (voice.profile) {
console.log(
'profile:',
voice.label,
voice.profile.speaker.dialect,
voice.profile.languages,
);
}
const model = TtsModel.Nebula;
const pcm = await client.synthesize('Hello from HUMAIN Voice', {
voice_id: voice.id,
model,
// This is an inactivity timeout applied while awaiting each audio chunk.
timeoutSeconds: 30,
onError: (error) => console.error('server error:', error.code, error.message),
});
await writeFile(outputPath, pcm16ToWav(pcm, getSampleRate(model)));
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
import wave
from pathlib import Path
from humain_voice import stt, tts
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
def write_pcm16_wav(path: Path, pcm: bytes, sample_rate: int) -> None:
with wave.open(str(path), "wb") as wav_file:
wav_file.setnchannels(1)
wav_file.setsampwidth(2)
wav_file.setframerate(sample_rate)
wav_file.writeframes(pcm)
def handle_error(error: stt.ErrorResponse | None) -> None:
if error is not None:
print("server error:", error.code, error.message)
async def main() -> None:
output_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.wav")
async with tts.TTSClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
) as client:
voices = await client.list_voices(timeout_seconds=5.0)
if not voices:
raise RuntimeError("No TTS voices are available")
voice = next((item for item in voices if item.get("profile")), voices[0])
if profile := voice.get("profile"):
print(
"profile:",
voice["label"],
profile["speaker"]["dialect"],
profile["languages"],
)
model = tts.TtsModel.Nebula
pcm = await client.synthesize(
"Hello from HUMAIN Voice",
voice_id=voice["id"],
model=model,
# This is an inactivity timeout applied while awaiting each chunk.
timeout_seconds=30.0,
on_error=handle_error,
)
write_pcm16_wav(output_path, pcm, tts.get_sample_rate(model))
if __name__ == "__main__":
asyncio.run(main())
```
A successful run has these observable outcomes:
1. Voice discovery returns at least one entry for this request.
2. Buffered synthesis receives the final audio chunk without a recorded server
error or inactivity timeout.
3. `speech.wav` starts with a valid RIFF/WAVE header followed by all returned
PCM bytes and can be opened by a WAV-capable player.
4. The JavaScript client closes in `finally`; Python exits its async client
context before writing the artifact.
If voice discovery returns no entries, the programs fail clearly and do not
create a misleading silent artifact.
## 3. Package raw PCM as WAV
The SDK return value is audio data, not a ready-made media file:
| Layer | Value used by the fixtures |
|---|---|
| SDK audio | Raw signed PCM16 little-endian, 24 kHz, mono |
| Sample width | 16 bits, or 2 bytes |
| WAV header | 44-byte RIFF/WAVE header with PCM format, channel count, sample rate, byte rate, block alignment, and data length |
| WAV body | Every PCM byte returned after synthesis reaches its final chunk |
Both programs obtain the sample rate through `getSampleRate(model)` /
`get_sample_rate(model)` instead of treating a container header as part of the
SDK response.
The JavaScript helper accepts the released `Uint8Array` directly and preserves
its `byteOffset` and `byteLength` when creating a Node.js `Buffer`. Python uses
the standard-library `wave` module to write the same metadata.
The 24 kHz PCM contract applies to Socket.IO TTS and these SDK clients. Read the
current operation contract before packaging bytes returned by another
transport.
## 4. Choose buffered or streaming synthesis
| Mode | API | Result and responsibility |
|---|---|---|
| Buffered | `synthesize()` | Returns one `Uint8Array` in JavaScript or `bytes` in Python after the SDK has collected audio through the final chunk. Simple for bounded files, but holds the complete PCM result in memory. |
| Streaming | `synthesizeStream()` / `synthesize_stream()` | Yields responses with `id`, `audio`, and `is_last`; process audio earlier, track total bytes, and finalize a valid container only after the final response. |
For either mode, the SDK has already removed the 17-byte Socket.IO TTS frame
header. Write each response's `audio` bytes, not the original framed payload.
An arbitrary network or iterator boundary is not completion; `is_last=true`
marks the final audio response.
Buffered synthesis can also receive chunks through `onAudio` / `on_audio`, but
the buffered call itself completes only after final audio is collected. If a
stream ends without a final chunk, do not publish the partial file as a complete
artifact.
## 5. Bound inactivity and preserve error state
| Runtime | Voice-list timeout | Synthesis timeout |
|---|---|---|
| JavaScript | 5-second default | `timeoutSeconds` defaults to 30 seconds of inactivity |
| Python | No default | No default; always pass `timeout_seconds` |
The fixtures explicitly use five seconds for voice discovery and 30 seconds for
synthesis. The synthesis value is an inactivity timeout while waiting for the
next audio chunk, not an overall workflow deadline. Add a separate app deadline
for connection, discovery, synthesis, file writing, and cleanup.
The service independently enforces a non-resetting 25-second overall synthesis
deadline and a 60-second inactivity watchdog. If the overall deadline wins
before final audio, it emits retryable `TTS_DEADLINE_EXCEEDED`; audio already
received remains partial.
TTS exposes two different error surfaces:
| Surface | Information retained |
|---|---|
| `onError` / `on_error` callback | Normalized `ErrorResponse`; structured payloads can retain `id`, `code`, `retryable`, `timestamp`, `retry_after_seconds`, `data`, `reason`, `retry_scope`, and `message`. A legacy non-object payload becomes a message. |
| Rejected synthesis | Generic JavaScript `Error` or Python `RuntimeError` containing the message only |
Record structured callback fields before cleanup. Do not infer retryability by
parsing the generic rejection message, and do not claim a retry is safe when the
callback does not provide enough state.
## 6. Clean up and publish atomically
Close the client even when voice discovery is empty, synthesis fails, the final
chunk never arrives, or file writing fails. The JavaScript fixture calls
`client.close()` in `finally`; the Python fixture uses `async with` to release
Socket.IO and its underlying HTTP resources.
Cleanup closes the client connection, which cancels active synthesis requests
owned by that connection and suppresses their later audio and error events.
It does not close inference connections shared with other requests.
For a production file workflow, write to a temporary destination and expose the
artifact only after final audio, a complete WAV header/body, and a successful
file close. Cleanup is still required if publishing the file fails.
## Next steps
---
# Transcribe a Recording with Speaker Labels
Locale: en
Source: https://docs.voice.humain.com/en/recipes/transcribe-a-recording
This recipe takes one complete recording through a production-shaped batch
workflow: submit, poll to a terminal state, reconcile speaker segments, write
captions, and clean up on every path.
## When to use this recipe
Use `BatchTranscribeClient` when the whole recording already exists, especially
for long-form or large media such as meetings, podcasts, calls, and archives.
Batch defaults bound each request at 512 MiB of request bytes and 4 hours of
decoded audio; Fast transcription has its own separate upload limits. A request
exactly at a configured limit is accepted and only a request that exceeds it is
rejected, but deployed limits can be lower than these defaults, so validate
representative media. The Batch API defines no result-retention duration, so
retrieve results promptly and don't design around an undocumented retention
window.
| Audio state | Choose | Why |
|---|---|---|
| Complete long-form recording | Batch transcription | Upload once and poll its job lifecycle |
| Complete short, latency-sensitive unit such as one conversational turn for a voice agent | Fast transcription | Send the complete payload over Socket.IO for lower latency |
| Audio is still arriving | Realtime transcription | Send PCM chunks and handle provisional and final results |
Fast transcription isn't the long-media path. Use batch for this meeting,
podcast, or archive workflow.
## Prerequisites
- `@humain-voice/sdk@0.18.0` or `humain-voice==0.18.0` installed.
- The `API_KEY` obtained through your organization's access flow and the
environment-rendered `API_URL`. Batch doesn't use `API_PATH`; Socket.IO
clients default to `/socket.io`.
- A complete supported audio file. The tested programs default to
`meeting.wav` and write `meeting.vtt`.
- A server-side JavaScript runtime or Python 3.10 or newer. The direct Python
polling example also uses `httpx`.
- A writable output directory and an app deadline appropriate for the
recording and worker environment.
The tested programs select `Language.ArEn` with
`BatchTranscriptionModel.BayanArEn`. Change the language and model together if
your recording requires another supported combination.
## 1. Run the tested SDK path
Choose one program and save it under the displayed filename. Both programs
enable diarization, poll every two seconds with a 300-second polling-loop
threshold, print the returned transcript, write finalized WebVTT, and close the
client in cleanup. Submission and an in-flight request can extend wall time.
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
BatchDiarization,
BatchTranscribeClient,
BatchTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.wav';
const outputPath = process.argv[3] ?? 'meeting.vtt';
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
api_version: process.env.API_VERSION ?? 'v1',
});
try {
const result = await client.transcribe(
await readFile(inputPath),
Language.ArEn,
{
asr: BatchTranscriptionModel.BayanArEn,
diarization: BatchDiarization.On,
saveResult: true,
pollInterval: 2,
timeout: 300,
onProgress: ({ status }) => console.info('status:', status),
},
);
console.info(result.results?.transcript ?? '');
await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.batchtranscription import BatchDiarization
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.vtt")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
api_version=os.environ.get("API_VERSION", "v1"),
) as client:
result = await client.transcribe(
input_path,
lang=stt.Language.ArEn,
asr=stt.BatchTranscriptionModel.BayanArEn,
diarization=BatchDiarization.On,
save_result=True,
poll_interval=2.0,
timeout_seconds=300.0,
on_progress=lambda response: print("status:", response.status.value),
)
print(result.results.transcript if result.results else "")
output_path.write_text(
stt.Subtitles.from_response(result).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
Run the program you saved:
- JavaScript / TypeScript in the Node.js 24 documentation verification
environment: `node batch-transcription.ts meeting.wav meeting.vtt`
- Python: `python batch_transcription.py meeting.wav meeting.vtt`
## 2. Confirm the expected artifacts
On a successful job:
| Artifact | Expected result |
|---|---|
| Terminal output | One or more `status:` updates, followed by the returned transcript |
| Batch result | Terminal status `done`, with normalized transcript offsets when the service recognizes speech |
| `meeting.vtt` | Finalized WebVTT generated by `Subtitles.fromResponse(result).toVtt()` |
| Diarization data | Speaker segments returned with the legacy result shape used by the released SDK |
Audio with no recognized speech can produce an empty transcript. Treat a
created caption file and a `done` job as successful processing. Validate whether
the content is useful separately.
The SDK helper succeeds on `done`, raises on `failed`, and reaches its configured
timeout while a job remains `queued`, `processing`, or `cleared`. It doesn't
surface `cleared` immediately. Use direct polling when the app must
distinguish that state as soon as it appears.
## 3. Bound direct API polling
After submitting `multipart/form-data` to
`POST /v1/transcribe/{lang}`, poll the recommended V2 result operation,
`GET /v1/transcribe/{job_id}`. The loop needs both a per-request timeout and an
overall deadline.
JavaScript / TypeScript
Python
```ts
// `jobId` is the value returned by the submission request in step 2.
const jobId = process.env.JOB_ID!;
const deadline = Date.now() + 5 * 60_000;
let job;
while (Date.now() < deadline) {
const response = await fetch(`${process.env.API_URL}/v1/transcribe/${jobId}?save_result=true`, {
headers: {
"x-api-key": process.env.API_KEY!,
Origin: process.env.API_URL!,
},
signal: AbortSignal.timeout(10_000),
});
if (!response.ok) throw new Error(`poll failed: HTTP ${response.status}`);
({ data: job } = await response.json());
if (job.status === "done") break;
if (job.status === "failed") {
throw new Error("transcription failed");
}
if (job.status === "cleared") {
throw new Error("transcription result is unavailable (cleared)");
}
await new Promise((resolve) => setTimeout(resolve, 2_000));
}
if (!job || job.status !== "done") throw new Error("poll deadline exceeded");
```
```python
import os
import time
import httpx
API_URL = os.environ["API_URL"]
API_KEY = os.environ["API_KEY"]
# `job_id` is the value returned by the submission request in step 2.
job_id = os.environ["JOB_ID"]
deadline = time.monotonic() + 5 * 60
job = None
with httpx.Client(timeout=10.0) as http:
while time.monotonic() < deadline:
response = http.get(
f"{API_URL}/v1/transcribe/{job_id}",
headers={"x-api-key": API_KEY, "Origin": API_URL},
params={"save_result": "true"},
)
response.raise_for_status()
job = response.json()["data"]
if job["status"] == "done":
break
if job["status"] == "failed":
raise RuntimeError("transcription failed")
if job["status"] == "cleared":
raise RuntimeError("transcription result is unavailable (cleared)")
time.sleep(2)
if job is None or job["status"] != "done":
raise TimeoutError("poll deadline exceeded")
```
`queued` and `processing` are non-terminal; `done`, `failed`, and `cleared` are
terminal. Use results only for `done`, surface the job failure for `failed`, and
treat `cleared` as an unavailable result.
These loops set `save_result=true` before terminal retrieval so a lost `done`
or `failed` response can be fetched again. The default `false` can clear stored
fields after building that response. The option does not guarantee a retention
duration.
The two-second interval, ten-second request timeout, and five-minute deadline
above are application choices, not service guarantees. Handle `429` using the
reported capacity and bounded backoff. Retry a result read only when
`save_result=true` preserved it; do not blindly repeat a timed-out upload
because it may already have created a job.
## 4. Reconcile words and speakers
The V2 response keeps `final_word_segments` and `diarization_segments`
separate. The following explicit application policy assigns a word to the
segment containing its midpoint. If there is no match, it preserves
`UNKNOWN_SPEAKER`.
JavaScript / TypeScript
Python
```ts
function speakerFor(word, segments) {
const midpoint = (word.start_time + word.end_time) / 2;
return segments.find(
(segment) =>
segment.start_time <= midpoint && midpoint < segment.end_time,
)?.speaker ?? "UNKNOWN_SPEAKER";
}
const attributed = job.final_word_segments.map((word) => ({
...word,
speaker: speakerFor(word, job.diarization_segments ?? []),
}));
```
```python
def speaker_for(word, segments):
midpoint = (word["start_time"] + word["end_time"]) / 2
segment = next(
(
item
for item in segments
if item["start_time"] <= midpoint < item["end_time"]
),
None,
)
return (segment or {}).get("speaker") or "UNKNOWN_SPEAKER"
attributed = [
{
**word,
"speaker": speaker_for(word, job.get("diarization_segments") or []),
}
for word in job["final_word_segments"]
]
```
Temporal midpoint matching is an application rule, not an identity guarantee.
Document a different nearest-segment or overlap rule if you choose one. Speaker
labels distinguish turns; they do not identify real people.
The legacy V1 route can return `speaker` directly on word offsets when its
force-alignment behavior is enabled. Keep V1 and V2 response types separate
rather than mixing their field names.
## 5. Produce subtitles
The tested SDK path already writes `meeting.vtt` from normalized word offsets.
Use `toSrt()` instead of `toVtt()` when the consumer requires SubRip. For a
direct V2 client, first normalize the returned word timing into the subtitle
renderer's input shape; do not pass the V2 wrapper to a helper that expects the
released SDK's legacy `TranscriptionResponse`.
Caption text and a speaker timeline are separate artifacts. WebVTT and SRT are
subtitle formats; RTTM is a diarization format.
## 6. Handle failure and cleanup
| Condition | Production action |
|---|---|
| Missing or invalid key | Stop and correct server-side configuration; do not expose the key in client code or logs |
| `429` | Read capacity information when present and apply bounded backoff with jitter |
| `failed` | Stop polling and surface the job error |
| `cleared` | Stop polling and report that the result is unavailable; do not infer a retention duration |
| Overall deadline | Stop the worker and record the job ID so the outcome can be investigated |
| Upload timeout with no `jobId` | Treat the outcome as ambiguous; do not blindly upload the same media again |
The verified JavaScript fixture closes its client in `finally`; the Python
fixture uses an async context manager. The direct Python poller uses a sync
context manager for its HTTP client. Preserve those cleanup boundaries when
adding storage, queues, or subtitle publishing.
## Next steps
If the SDK path fits, re-run it against representative recordings and exercise
deadlines, retries, and cleanup. If your worker owns submission and polling
separately, continue to the Batch REST contract before implementing the upload
side.
---
# SDK Overview
Locale: en
Source: https://docs.voice.humain.com/en/sdk
Use this page to choose a workload and runtime. Then move to the JavaScript or
Python guide for exact constructors, options, response fields, event constants,
and tested programs. The Go SDK is released from the same contract and links to
its source documentation below.
**Released contract:** these docs target exactly
`@humain-voice/sdk@0.18.0`, `humain-voice==0.18.0`, and the Go module tagged
`golang/v0.18.0`. The SDKs wrap Batch REST and Socket.IO services; they do not
wrap Realtime HTTP operations. This release adds public constants and TTS error
classification for content-policy rejection and moderation unavailability.
## Choose by task
Start with the shape of the audio, not the client name:
| Input and goal | Choose | Why |
|---|---|---|
| A complete recording, especially a longer meeting, interview, or podcast | Batch transcription (`BatchTranscribeClient`) | Upload once, receive a job ID, and poll to a terminal status with an app deadline. |
| A complete latency-sensitive audio unit, such as one conversational turn for an AI agent | Fast transcription (`FastTranscriptionClient`) | Send the already-complete unit over Socket.IO and receive partial and final transcription updates. |
| Audio that is still arriving from a microphone, call, or live source | Realtime ASR (`RealtimeClient`) | Feed PCM16 chunks and reconcile provisional, final, and speech-final text. |
| A live speaker timeline | Realtime diarization (`RealtimeDiarizationClient`) | Feed audio while consuming reconciled speaker-segment updates. |
| Text that should become speech | Socket.IO TTS (`TTSClient`) | Discover a voice, then receive synthesized PCM16 audio chunks. |
Fast transcription is for a bounded, complete, latency-sensitive unit. It is
not the path for a long recording or podcast; use Batch for those workloads.
`Subtitles` shapes completed word timing after you choose a transcription
client. `RealtimeSubtitles` is also exported, but its `id:seq` deduplication
requires the wire to provide distinct sequence values; see the finality section
below. They are result helpers, not transport clients.
If you need direct HTTP streaming instead of an SDK client, use the
[Realtime HTTP guide](/en/api-guides/realtime-http).
## Choose a server runtime
| Language guide | Exact release | Runtime contract |
|---|---|---|
| [JavaScript and TypeScript](/en/sdk/javascript) | `@humain-voice/sdk@0.18.0` | ES2021 plus `fetch`, `FormData`, and `Blob`; the SDK README names server-side Node.js and Bun |
| [Python](/en/sdk/python) | `humain-voice==0.18.0` | Python 3.10 or newer |
| [Go](https://gitlab.humain.com/humain/data-and-ai-modeling/library/sautech-sdk/-/tree/golang/v0.18.0/golang) | `golang/v0.18.0` | Go 1.25 module with package documentation and examples in the tagged source |
### Handle TTS content-policy outcomes
| Wire code | JavaScript / Python export | Go `errcodes` export | Retry |
|---|---|---|---|
| `TTS_INPUT_NOT_ALLOWED` | `TTS_INPUT_NOT_ALLOWED` | `TTSInputNotAllowed` | No; change the text |
| `TTS_MODERATION_UNAVAILABLE` | `TTS_MODERATION_UNAVAILABLE` | `TTSModerationUnavailable` | Yes, with bounded backoff |
The JavaScript `isTtsCode()` / `isTtsOwned()`, Python `is_tts_code()` /
`is_tts_owned()`, and Go `IsTTSCode()` / `IsTTSOwned()` helpers classify both
codes as TTS-owned. Preserve the structured callback before the synthesis call
rejects with its generic message-only error.
The JavaScript package does not publish a minimum Node.js or Bun version. The
documentation fixtures run under Node.js 24 and Bun 1.3.14; those versions
describe the docs verification environment, not an SDK support promise.
Use `humain_voice` for new Python code. The historical `sautech` namespace in
`0.18.0` remains a compatibility import and emits a deprecation warning.
## Configure release 0.18.0
Set the values issued for your environment in a trusted server runtime:
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
```
Batch uses `API_URL`, `API_KEY`, and `API_VERSION`. Socket.IO clients require
only `API_URL` and `API_KEY` and default to `/socket.io`. Set `API_PATH` only
when a deployment uses an override; the legacy `sautech.humain.com` endpoint
requires `/realtime/socket.io`.
See [Authentication](/en/authentication) for your organization's credential
flow and server-side key handling.
## Own lifecycle and deadlines
### Close the stream and its client
A successful stream close usually releases its Socket.IO session when no
request contexts remain. A routed error can remove its request context before
`close()` runs, so the owning scope must still clean up the client.
Use `finally` for JavaScript clients. In Python, use the supported async or
synchronous context manager where the language guide shows it. Stop sending
audio after an error and disconnect even when a per-stream close has already
returned.
### Set a deadline for each operation
- **Batch:** `transcribe` polls every 2 seconds with a 300-second default
polling-loop threshold. Submission and an in-flight request can extend wall
time. The helper does not stop on `cleared` and instead reaches the threshold.
- **Fast transcription:** JavaScript has no SDK request-timeout option. Python
defaults to 60 seconds. Keep an application deadline in either runtime.
- **Realtime ASR:** stream close waits up to 1 second for the final result by
default. Expiry ends the wait; it does not prove that a final result arrived.
- **Realtime diarization:** close waits up to 5 seconds and returns the
best-known reconciled timeline if the final-result wait expires.
- **Voice list and TTS:** JavaScript defaults to 5 seconds for voice listing and
30 seconds of inactivity for synthesis. Python applies no timeout unless you
pass one. These are client controls; the service also enforces a non-resetting
25-second overall synthesis deadline and a 60-second inactivity watchdog.
Handle an empty voice list and close the client in both runtimes.
## Interpret results by stage
### Distinguish provisional and terminal results
- **Batch:** treat `done`, `failed`, and `cleared` as terminal in an
application-owned poller. The released `transcribe` helper succeeds on
`done`, raises on `failed`, and does not terminate early on `cleared`.
- **Fast transcription:** use `is_final` to replace partial text with the final
result for the complete audio unit.
- **Realtime ASR:** a result is provisional while both `is_final` and
`is_speech_final` are false. Replace provisional UI text instead of appending
it as a second transcript.
- **Realtime diarization:** `segments` is the reconciled timeline;
`newlyFinalized` / `newly_finalized` is only the new final delta.
- **TTS:** collect or stream audio until `is_last`; the returned bytes are raw
PCM16, not a WAV container.
### Generate subtitles only from finalized timing
Batch `Subtitles.fromResponse()` in JavaScript and `result.subtitles()` in
Python read normalized word offsets and render SRT or WebVTT.
`RealtimeSubtitles` ignores partial responses and deduplicates final responses
by `id:seq`. The current Realtime wire contract does not guarantee distinct
`seq` values, so collect final-event words in arrival order and render them with
`Subtitles` when a stream can produce multiple final events. The app still owns
provisional on-screen text.
Speaker segments are a different output. Export them with `toRttm()` in
JavaScript or `to_rttm()` in Python, or reconcile them with finalized ASR words
when producing speaker-attributed captions.
### Preserve structured errors before retrying
Batch HTTP exceptions expose typed status, code, retryability, capacity, and
retry-delay fields using `statusCode` / `retryAfter` in JavaScript and
`status_code` / `retry_after` in Python when available.
Fast transcription and TTS error callbacks can retain a structured
`ErrorResponse`. Their rejected JavaScript promises or Python calls use generic
message-only errors on the routed failure path, so record structured callback
fields before cleanup.
`maxRetries` / `max_retries` is deprecated and ignored in `0.18.0`. Add bounded
retry policy in the application and do not blindly repeat an ambiguous upload.
See [Errors and Rate Limits](/en/api-guides/errors-and-rate-limits).
## Next steps
Choose one guide and follow its tested program for your selected client. The
language pages are the reference for exact public methods and language-specific
cleanup; this overview is the decision map.
} href="/en/sdk/javascript" title="JavaScript and TypeScript" description="Install the exact release, inspect the public client surface, and run compiled task examples." />
} href="/en/sdk/python" title="Python" description="Choose async or supported sync methods, inspect exact imports, and run type-checked task examples." />
---
# JavaScript and TypeScript
Locale: en
Source: https://docs.voice.humain.com/en/sdk/javascript
This guide targets the exact `javascript/v0.18.0` release tag. Its six programs
are compiled against that tag and render from the same tested source files.
## Install and configure
Install the documented release:
```bash
npm install @humain-voice/sdk@0.18.0
```
The package targets ES2021 and uses `fetch`, `FormData`, and `Blob`. It does not
declare a minimum Node.js or Bun version. The documentation fixtures are checked
with Node.js 24 and Bun 1.3.14; those are verification environments, not an SDK
support promise.
Set the values issued for your environment:
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
```
Socket.IO clients require only `api_url` and `api_key`; release `0.18.0`
defaults `api_path` to `/socket.io`. Pass a path only for a self-hosted or
proxied deployment that uses an override, or for the legacy
`sautech.humain.com` endpoint, which requires `/realtime/socket.io`. Keep
`API_KEY` in server-side configuration.
A successful example produces an application result, not only a connection:
batch writes WebVTT, fast writes SRT, realtime writes finalized WebVTT, live
diarization returns a reconciled timeline, and TTS writes a playable WAV file.
## Choose a client
| Task | Client | Choose it when |
|---|---|---|
| Transcribe a complete recording | `BatchTranscribeClient` | The full file already exists, especially a longer meeting, podcast, call, or archive item |
| Transcribe a short complete audio unit with lower latency | `FastTranscriptionClient` | The complete payload is already available, such as one agentic conversation turn |
| Transcribe audio while it arrives | `RealtimeClient` | A microphone, call, or live source is still producing audio |
| Build a live speaker timeline | `RealtimeDiarizationClient` | You need evolving and finalized speaker segments |
| Generate speech | `TTSClient` | You need streamed PCM output from text |
Fast transcription is not the long-form path. Use batch for meetings, podcasts,
and archive media; use fast for short, already-complete, latency-sensitive audio
units.
## Transcribe a complete recording
The tested batch program enables diarization, polls with a 300-second
polling-loop threshold, prints the transcript, and writes finalized WebVTT.
Submission and an in-flight request can extend wall time.
| Contract | Released `0.18.0` behavior |
|---|---|
| Constructor | `new BatchTranscribeClient({ api_url, api_key, api_version="v1", maxRetries? })` |
| Accepted audio | `ArrayBuffer`, `Uint8Array`, `Blob`, or `File` |
| Operations | `submit()`, `getResult()`, `transcribe()`, `close()` |
| Options | `submit`: `diarization`, `asr`, `itn`, `redact`; `getResult`: `saveResult`; `transcribe`: those options plus `pollInterval` (2 s), `timeout` (300 s), `onProgress`, `saveResult` |
| Result and finality | `submit()` returns `JobResponse`; the helper succeeds on `done`, raises on `failed`, and times out while a job remains `queued`, `processing`, or `cleared` |
| Cleanup and errors | `close()` is public and currently a no-op. `maxRetries` is deprecated and ignored; batch failures use the typed hierarchy described in the retry section. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
BatchDiarization,
BatchTranscribeClient,
BatchTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.wav';
const outputPath = process.argv[3] ?? 'meeting.vtt';
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
api_version: process.env.API_VERSION ?? 'v1',
});
try {
const result = await client.transcribe(
await readFile(inputPath),
Language.ArEn,
{
asr: BatchTranscriptionModel.BayanArEn,
diarization: BatchDiarization.On,
saveResult: true,
pollInterval: 2,
timeout: 300,
onProgress: ({ status }) => console.info('status:', status),
},
);
console.info(result.results?.transcript ?? '');
await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
Use `submit(audio, language, options)` and
`getResult(jobId, language, options)` when a worker or queue owns polling. A
custom poller must stop on `done`, `failed`, and `cleared` explicitly.
The default `saveResult=false` can clear a `done` or `failed` result after the
response is built. Set `saveResult: true` before polling when terminal delivery
must survive a lost response; the API does not specify a retention duration.
`Subtitles.fromResponse(result)` reads `result.results.offsets`; use `toSrt()`
or `toVtt()`. Batch responses also expose `diarization_segments` when returned
by the legacy result route.
## Transcribe a short complete audio unit
Fast transcription sends the **complete** audio payload once over Socket.IO. It
is optimized for latency-sensitive short units such as an agentic conversation
turn; it is not the long-meeting or podcast client.
| Contract | Released `0.18.0` behavior |
|---|---|
| Constructor | `new FastTranscriptionClient({ api_url, api_key, api_path?, onConnect?, onFileUpload?, onError? })` |
| Accepted audio | `ArrayBuffer`, `Uint8Array`, or `Blob` containing the complete audio payload |
| Operations | `connect()`, `transcribe()`, `close()` |
| Call | `transcribe(audio, language, model, { onResponse?, onFileUpload?, onError?, diarizationModel?, itnModel?, redactModel? })` |
| Result and finality | `onFileUpload` receives the upload acknowledgment; `onResponse` can receive partials before the final `FtTranscribeResponse`. The promise returns the final response or `undefined`. |
| Deadline, cleanup, and errors | There is no SDK timeout option. Apply an app deadline and close explicitly. A routed request error calls `onError` and then rejects with a generic message-only `Error`. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
FastTranscriptionClient,
FastTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function withDeadline(operation: Promise, milliseconds: number): Promise {
let timer: ReturnType | undefined;
try {
return await Promise.race([
operation,
new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error('Fast transcription deadline exceeded')), milliseconds);
}),
]);
} finally {
if (timer) clearTimeout(timer);
}
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'short-call.wav';
const outputPath = process.argv[3] ?? 'short-call.srt';
const client = new FastTranscriptionClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
await client.connect();
const result = await withDeadline(
client.transcribe(
await readFile(inputPath),
Language.Ar,
FastTranscriptionModel.BayanAr,
{
onFileUpload: (response) => console.info('uploaded:', response?.id),
onResponse: (response) => {
console.info(response.is_final ? 'final:' : 'partial:', response.transcription);
},
onError: (error) => console.error('server error:', error.code, error.message),
},
),
60_000,
);
if (!result) throw new Error('Fast transcription ended without a final result');
await writeFile(outputPath, Subtitles.fromResponse(result).toSrt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
The fixture rejects an absent final result and writes SRT only after finality.
Do not blindly resubmit after an ambiguous deadline: the API publishes no
idempotency-key contract. SDK `0.18.0` exposes `diarizationModel`, `itnModel`,
and `redactModel` for wire compatibility, but the validated public Fast service
does not apply them. Omit them; use Batch when those processing options are
required.
## Transcribe audio while it arrives
Realtime input is PCM16 little-endian, 16 kHz, mono. The tested program sends
3,200-byte chunks, representing 100 ms of audio, and writes finalized WebVTT.
| Contract | Released `0.18.0` behavior |
|---|---|
| Constructor | `new RealtimeClient({ api_url, api_key, api_path? })`; the client also exposes handler properties |
| Operations | `connect()`, `startStream()`, `disconnect()` |
| Start | `startStream(language, { onConnect?, onDisconnect?, onResponse?, onError?, subtitles? })` |
| Stream | `send(audio, isLast=false)`, `close(timeoutSeconds=1)`, `stop()` |
| Result and finality | `RtTranscribeResponse` carries `seq`, `is_final`, and `is_speech_final`; `is_speech_final` marks an utterance boundary, while only protocol-level `is_final` ends the stream |
| Cleanup and errors | `close()` sends the terminator and waits; `stop()` removes the stream without that wait. A routed error can remove the stream context, so always call client-level `disconnect()` in `finally`. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
type ErrorResponse,
Language,
RealtimeClient,
Subtitles,
type WordSegment,
} from '@humain-voice/sdk';
const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'speech.pcm';
const outputPath = process.argv[3] ?? 'speech.vtt';
const client = new RealtimeClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
const finalizedWords: WordSegment[] = [];
let serverError: ErrorResponse | undefined;
let protocolFinalObserved = false;
try {
const stream = await client.startStream(Language.ArEn, {
onResponse: (response) => {
const kind = response.is_final
? 'final'
: response.is_speech_final
? 'speech-final'
: 'partial';
console.info(`${kind}:`, response.transcription);
if (response.is_final) protocolFinalObserved = true;
if (response.is_final || response.is_speech_final) {
// The current public Realtime contract does not guarantee increasing
// seq values, so collect final words in arrival order instead of
// asking RealtimeSubtitles to deduplicate by id:seq.
finalizedWords.push(...response.words);
}
},
// The released SDK can invoke a stream handler more than once for one
// routed error, so keep this callback idempotent.
onError: (error) => {
serverError = error;
},
});
const pcm = await readFile(inputPath);
for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
await pause(100);
}
// close() sends the last frame and waits for protocol is_final, a routed
// error, or this timeout. It resolves rather than throwing on timeout.
await stream.close(5);
if (serverError) {
throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
}
if (!protocolFinalObserved) {
throw new Error('Realtime stream ended before protocol is_final');
}
await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
Replace provisional text in observed arrival order until a speech boundary,
but keep the stream open until protocol-level `is_final`. The fixture collects final-event words itself and renders them with
`Subtitles`; it does not rely on `seq`, whose ordering and uniqueness are not
part of the current public wire contract. `RealtimeSubtitles` deduplicates by
`id:seq` and can collapse distinct final events under that contract.
`stream.close(timeoutSeconds)` waits for protocol-level `is_final`, a routed
error, or its timeout. It resolves rather than throws when that timeout expires;
`is_speech_final` does not release the wait.
## Build a live speaker timeline
The SDK accumulates final-segment deltas and replaces the active tail to expose
one reconciled `update.segments` timeline.
| Contract | Released `0.18.0` behavior |
|---|---|
| Constructor | `new RealtimeDiarizationClient({ api_url, api_key, api_path? })` |
| Operations | `connect()`, `startStream()`, `disconnect()` |
| Start options | `language` defaults to `Language.Ar`; connection, update, and error callbacks are optional |
| Stream | Exposes `streamId`, `speakers`, `send()`, `close(5)`, and one async iterator |
| Result and finality | `DiarizationUpdate` contains reconciled `segments`, `newlyFinalized`, `activeSegments`, `isFinal`, and `raw` |
| Cleanup and errors | Consume updates while sending audio, then disconnect. Iterator failures are `DiarizationStreamError`; `close(5)` returns the best-known timeline if the final wait expires, but it does not end a waiting iterator on that timeout path. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
DIARIZATION_RECOMMENDED_CHUNK_BYTES,
RealtimeDiarizationClient,
type SpeakerSegment,
toRttm,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.pcm';
const outputPath = process.argv[3] ?? 'meeting.rttm';
const client = new RealtimeDiarizationClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
let finalObserved = false;
const stream = await client.startStream({
onError: (error) => console.error('server error:', error.code, error.message),
onUpdate: (update) => {
finalObserved ||= update.isFinal;
for (const segment of update.newlyFinalized) {
console.info(segment.speaker, segment.start_time, segment.end_time);
}
},
});
const pcm = await readFile(inputPath);
if (pcm.length === 0 || pcm.length % 2 !== 0) {
throw new Error('Input must be nonempty PCM16 with an even byte length');
}
for (
let offset = 0;
offset < pcm.length;
offset += DIARIZATION_RECOMMENDED_CHUNK_BYTES
) {
await stream.send(
pcm.subarray(offset, offset + DIARIZATION_RECOMMENDED_CHUNK_BYTES),
);
await pause(480);
}
// close() returns the best-known reconciled timeline after five seconds,
// even when no isFinal update arrived. A callback avoids leaving an async
// iterator waiting forever on that timeout path.
const timeline: SpeakerSegment[] = await stream.close(5);
const destination = finalObserved ? outputPath : `${outputPath}.partial`;
await writeFile(destination, toRttm(timeline, 'meeting'), 'utf8');
if (!finalObserved) {
console.warn(`Final result not observed; wrote incomplete output to ${destination}`);
}
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
`DIARIZATION_RECOMMENDED_CHUNK_BYTES` is 15,360 bytes, or 480 ms at the
required audio format. Consuming only after the feed finishes can stall the
workflow. The fixture uses `onUpdate` so timeout cleanup cannot leave an iterator
waiting; it writes a `.partial` RTTM file unless `isFinal` was observed.
## Generate speech and write WAV
`listVoices()` returns multilingual `{ id, label, profile }` entries. The
profile contains shared `speaker` metadata and an open-ended `languages` list;
pass its `id` as `voice_id`. Handle an empty list before synthesis. Socket.IO TTS returns raw
PCM16 little-endian, 24 kHz, mono bytes, not a WAV container.
For the current Arabic/English profiles, any Arabic-script letter in `text`
selects Arabic; otherwise English is selected. Physical variant IDs are
internal and rejected.
| Contract | Released `0.18.0` behavior |
|---|---|
| Constructor | `new TTSClient({ api_url, api_key, api_path?, verbose?, onConnect?, onError? })`; `verbose` is accepted but has no behavior |
| Operations | `connect()`, `listVoices()`, `synthesize()`, `synthesizeStream()`, `close()` |
| Inputs | Text containing at least one Unicode letter or number after trimming, and exactly one of `voice_id` or non-empty `voice_references`; for the public route, send one `{ text, audio }` reference whose `audio` is standard-base64 RIFF/WAVE with non-empty mono PCM16 data |
| Defaults | Voice-list timeout 5 s; `model=TtsModel.Nebula`; `timeoutSeconds=30` seconds of inactivity |
| Other options | `onAudio` on the buffered call only, `onError`, and `request_id` |
| Result, cleanup, and errors | `TtsAudioResponse` is `{ id, is_last, audio: Uint8Array }`. Close explicitly. `onError` receives normalized structured data, while a rejected synthesis promise is a generic message-only `Error`. |
```ts
import { writeFile } from 'node:fs/promises';
import {
TTSClient,
TtsModel,
getSampleRate,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
function pcm16ToWav(pcm: Uint8Array, sampleRate: number): Buffer {
const header = Buffer.alloc(44);
header.write('RIFF', 0);
header.writeUInt32LE(36 + pcm.byteLength, 4);
header.write('WAVE', 8);
header.write('fmt ', 12);
header.writeUInt32LE(16, 16);
header.writeUInt16LE(1, 20); // Linear PCM.
header.writeUInt16LE(1, 22); // Mono.
header.writeUInt32LE(sampleRate, 24);
header.writeUInt32LE(sampleRate * 2, 28);
header.writeUInt16LE(2, 32);
header.writeUInt16LE(16, 34);
header.write('data', 36);
header.writeUInt32LE(pcm.byteLength, 40);
return Buffer.concat([
header,
Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength),
]);
}
async function main(): Promise {
const outputPath = process.argv[2] ?? 'speech.wav';
const client = new TTSClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
const voices = await client.listVoices({ timeoutSeconds: 5 });
const voice = voices.find((candidate) => candidate.profile) ?? voices[0];
if (!voice) throw new Error('No TTS voices are available');
if (voice.profile) {
console.log(
'profile:',
voice.label,
voice.profile.speaker.dialect,
voice.profile.languages,
);
}
const model = TtsModel.Nebula;
const pcm = await client.synthesize('Hello from HUMAIN Voice', {
voice_id: voice.id,
model,
// This is an inactivity timeout applied while awaiting each audio chunk.
timeoutSeconds: 30,
onError: (error) => console.error('server error:', error.code, error.message),
});
await writeFile(outputPath, pcm16ToWav(pcm, getSampleRate(model)));
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
Use `synthesizeStream()` to process `response.audio` as it arrives. A structured
error retains `code` and `retryable`; a legacy non-object payload normalizes to
`{ message }`. The fixture preserves the `Uint8Array` byte range and adds the
correct WAV header.
The service independently enforces a non-resetting 25-second overall synthesis
deadline and a 60-second inactivity watchdog. If the overall deadline wins,
`TTS_DEADLINE_EXCEEDED` is retryable and any audio already received is partial.
Public TTS helpers are `TtsModel.Nebula`, `DEFAULT_SAMPLE_RATE`,
`MODEL_SAMPLE_RATES`, `getSampleRate()`, and `decodeTtsAudioFrame()`.
## Retry a preserved batch read
SDK `0.18.0` makes one HTTP call per batch operation. This fixture retries a
result read with bounded exponential backoff and passes `saveResult: true`
before terminal retrieval. Without that option, a lost terminal response can
be followed by `cleared`, so the default read is not universally idempotent.
| Exception | Released fields |
|---|---|
| `BatchTranscribeError` | `statusCode`, `payload`, `code`, `retryable`, `jobId`, `detail`, `timestamp`, `capacity`, `rawBody` |
| `BatchTranscribeAuthError` | Authentication failure subtype |
| `BatchTranscribeTimeoutError` | Adds `elapsed` |
| `BatchTranscribeJobFailedError` | Adds `error` and `errorCode` |
| `BatchTranscribeRateLimitError` | Adds `retryAfter` |
```ts
import {
BatchTranscribeClient,
BatchTranscribeError,
BatchTranscribeRateLimitError,
Language,
type TranscriptionResponse,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function getResultWithRetry(
client: BatchTranscribeClient,
jobId: string,
attempts = 5,
): Promise {
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
// saveResult prevents a terminal read from clearing the stored result
// before a retry. It does not establish a retention duration.
return await client.getResult(jobId, Language.ArEn, { saveResult: true });
} catch (error: unknown) {
if (!(error instanceof BatchTranscribeError)) throw error;
const rateLimited = error instanceof BatchTranscribeRateLimitError;
const retryable = rateLimited || error.retryable === true;
console.error({
statusCode: error.statusCode,
code: error.code,
capacity: error.capacity,
});
if (!retryable || attempt === attempts) throw error;
const serverDelayMs = rateLimited && error.retryAfter !== undefined
? error.retryAfter * 1_000
: 0;
const exponentialDelayMs = 500 * 2 ** (attempt - 1);
await pause(Math.max(serverDelayMs, exponentialDelayMs) + Math.random() * 250);
}
}
throw new Error('Retry loop exhausted');
}
async function main(): Promise {
const jobId = process.argv[2];
if (!jobId) throw new Error('Pass a batch job ID as the first argument');
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
});
try {
const result = await getResultWithRetry(client, jobId);
console.info(result.status, result.results?.transcript ?? '');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
`maxRetries` is deprecated and ignored. Do not apply this loop blindly to job
submission: after a timeout, the client may not know whether the upload created
a job.
## Released response and helper reference
| Type or helper | Released fields / behavior |
|---|---|
| `JobResponse` | `jobId`, `status` |
| `TranscriptionResponse` | `status`; optional `results`, `APIVersion`, `version`, `metadata`, `diarization_segments`, `error`, `errorCode`. Results contain `transcript` and offsets; metadata contains `sautechVersion`, `jobId`, `fileDuration`. |
| Batch helpers | `isComplete`, `isFailed`, `isPending`, `getJobId`, `getFileDuration`; `BatchDiarization`, `BatchRedact`, and status/model constants are exported. |
| `FileUploadedResponse` / `FtTranscribeResponse` | Upload: `id`, optional `message`. Fast result: `id`, `seq`, `transcription`, `words`, `is_final`. |
| `RtTranscribeResponse` | Fast result fields plus `is_speech_final`. |
| `DiarizationUpdate` | `id`, reconciled `segments`, `newlyFinalized`, `activeSegments`, `isFinal`, `raw`. |
| `SpeakerContext` / `VoiceProfile` / `VoiceInfo` | `{ gender, dialect }`; `{ speaker, languages }`; `{ id, label, profile? }`. The current API always supplies `profile`. |
| `VoiceReference` / `TtsAudioResponse` | `{ text, audio }`; `{ id, is_last, audio: Uint8Array }`. |
| `ErrorResponse` | Optional `id`, `message`, `code`, `retryable`, `timestamp`, `retry_after_seconds`, `data`, `reason`, and `retry_scope`; `parseErrorResponse()` normalizes legacy non-object payloads. |
An unrouteable socket error can reach only the global callback. Keep an
application deadline and always clean up. Fast request errors call `onError`
then reject with a generic `Error`; realtime signals its callback/final wait;
diarization iterators throw `DiarizationStreamError`; TTS callbacks retain
structured data but rejected synthesis promises keep only the message.
## Low-level event and error exports
The top-level package exports `generateUuid()`, the live/fast frame encoders,
and flag constants.
| Event exports | Wire values |
|---|---|
| `EVENT_FT_ERROR`, `EVENT_FT_TRANSCRIBE_FILE`, `EVENT_FT_TRANSCRIBE_FILE_UPLOAD_SUCCESS`, `EVENT_FT_TRANSCRIBE_RESULT` | `error`, `audio_file`, `audio_file_upload_success`, `transcription_result` |
| `EVENT_RT_AUDIO_STREAM`, `EVENT_RT_END_AUDIO_STREAM` | `audio_stream`, `end_audio_stream` |
| `EVENT_DIARIZATION_STREAM`, `EVENT_DIARIZATION_RESULT` | `diarization_stream`, `diarization_result` |
| `EVENT_TTS_REQUEST`, `EVENT_TTS_AUDIO`, `EVENT_TTS_ERROR` | `tts`, `tts_audio`, `error` |
| `EVENT_TTS_VOICE_LIST_REQUEST`, `EVENT_TTS_VOICE_LIST_RESULT` | `tts_voice_list`, `tts_voice_list_result` |
| Error-code group | Constants |
|---|---|
| Authentication | `AUTH_UNAUTHORIZED`, `AUTH_KEY_INVALID`, `AUTH_FORBIDDEN` |
| Validation | `VALIDATION_INVALID_LANGUAGE`, `VALIDATION_INVALID_FORMAT`, `VALIDATION_REQUIRED_FIELD`, `VALIDATION_FILE_CORRUPT`, `VALIDATION_INVALID_PARAM`, `VALIDATION_INVALID_UUID` |
| Limits and billing | `RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`, `CONCURRENCY_LIMIT_EXCEEDED`, `CREDITS_EXHAUSTED`, `BILLING_AUTHORIZATION_UNAVAILABLE`, `PAYLOAD_TOO_LARGE`, `AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`, `CHARACTER_COUNT_EXCEEDED`, `VOICE_REFERENCE_COUNT_EXCEEDED`, and the exported `SESSION_*` codes |
| ASR | `ASR_TRANSCRIPTION_FAILED`, `ASR_MODEL_NOT_FOUND`, `ASR_MODEL_UNAVAILABLE`, `ASR_STREAM_EXPIRED`, `ASR_UNSUPPORTED_CODEC`, `ASR_STREAM_NOT_FOUND` |
| TTS | `TTS_SYNTHESIS_FAILED`, `TTS_DEADLINE_EXCEEDED`, `TTS_MODEL_NOT_FOUND`, `TTS_VOICE_NOT_FOUND`, `TTS_VOICE_RESOLUTION_FAILED`, `TTS_VOICE_LIST_FAILED`, `TTS_INPUT_NOT_ALLOWED`, `TTS_MODERATION_UNAVAILABLE`, `TTS_MODEL_UNAVAILABLE`, `TTS_INVALID_INPUT` |
| Speaker and diarization | `SPEAKER_ID_FAILED`, `DIARIZATION_FAILED`, `DIARIZATION_MODEL_NOT_FOUND` |
| Server, batch, and compatibility | `SERVER_INTERNAL`, `SERVER_DEPENDENCY_FAILURE`, `METHOD_NOT_ALLOWED`, `TRANSCRIPTION_JOB_NOT_FOUND`, `RATE_LIMITED`, `VALIDATION_FAILED`, `INTERNAL_ERROR` |
Workload-limit, billing, and TTS content-policy errors are routed to the active
request context in `0.18.0`. Fast and TTS requests reject after their structured callbacks;
Realtime invokes `onError` and releases its final wait; diarization surfaces a
`DiarizationStreamError` from the iterator. Read `data` for limit evidence,
honor `retry_after_seconds` for retryable pressure, and open a fresh stream when
`ASR_STREAM_EXPIRED` carries `retry_scope: "new_stream"`.
Use `isAsrCode()`, `isTtsCode()`, `isRequestScopedCode()`,
`isRealtimeOwned()`, `isTtsOwned()`, `isDiarizationCode()`, and
`isDiarizationOwned()` to route structured socket errors. These classifiers do
not replace a workflow deadline or cleanup for an unrouteable error.
## Subtitle reference
| API | Contract |
|---|---|
| `Subtitles` | `SubtitleCue`, `SubtitleOptions`, `SubtitleRenderOptions`, `SubtitleError`; constructor from cues; `cues`; `fromWords`, `fromCues`, `fromResponse`; `toSrt`, `toVtt` |
| `RealtimeSubtitles` | `words`, `cues`, `addResponse`, `subtitles`, `toSrt`, `toVtt`; ignores partials and deduplicates finalized `id:seq` responses |
| Top-level helpers | `wordsToCues`, `cuesToSrt`, `cuesToVtt`, `subtitles`, `toSrt`, `toVtt` |
| Shaping defaults | `maxDurationSeconds=6`, `maxGapSeconds=0.7`, `minDurationSeconds=0.5`, `maxCharsPerLine=42`, `maxLines=2`, `splitOnSpeakerChange=true`, `strict=false`; SRT `startIndex=1` |
Subtitle input accepts batch camel-case offsets and realtime snake-case words.
Use strict mode when malformed or out-of-order timing must fail rather than be
normalized or skipped.
## Next steps
---
# Python
Locale: en
Source: https://docs.voice.humain.com/en/sdk/python
This guide targets exactly **`humain-voice==0.18.0`** on Python 3.10 or
newer. Its displayed programs are parsed and type-checked against the
`python/v0.18.0` release tag.
## Install and configure
Install the pinned package in your server-side environment or virtual
environment:
```bash
python -m pip install humain-voice==0.18.0
```
Set the values issued for your environment:
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
```
Import new code through `humain_voice`. The historical `sautech` namespace is
a deprecated compatibility import in `0.18.0` and emits a warning.
Batch uses `API_URL`, `API_KEY`, and `API_VERSION`. Socket.IO clients require
only `api_url` and `api_key`; `api_path` defaults to `/socket.io`. Pass a path
only for a deployment override; the legacy `sautech.humain.com` endpoint
requires `/realtime/socket.io`.
Every Python client supports async cleanup plus async and synchronous context
managers. Method coverage is not symmetrical: use only the sync methods named
for each client below. There are no public `connect_sync()` or
`disconnect_sync()` methods.
## First task: transcribe a complete recording
Start with `BatchTranscribeClient` when the complete recording already exists,
especially for a long meeting, podcast, interview, or archive file. Save this
tested source as `batch_transcription.py` beside an input recording:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.batchtranscription import BatchDiarization
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.vtt")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
api_version=os.environ.get("API_VERSION", "v1"),
) as client:
result = await client.transcribe(
input_path,
lang=stt.Language.ArEn,
asr=stt.BatchTranscriptionModel.BayanArEn,
diarization=BatchDiarization.On,
save_result=True,
poll_interval=2.0,
timeout_seconds=300.0,
on_progress=lambda response: print("status:", response.status.value),
)
print(result.results.transcript if result.results else "")
output_path.write_text(
stt.Subtitles.from_response(result).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
Run it with an input file and output path:
```bash
python batch_transcription.py meeting.wav meeting.vtt
```
A successful run reports job progress, prints the final transcript, and writes
finalized WebVTT cues to `meeting.vtt`.
### Released Batch surface
| Surface | `0.18.0` contract |
|---|---|
| Constructor | `BatchTranscribeClient(api_url, api_key, max_retries=0, api_version="v1")` |
| Async methods | `submit()`, `get_result()`, `transcribe()`, `close()` |
| Sync methods | `submit_sync()`, `get_result_sync()`, `transcribe_sync()`, `close_sync()` |
| Options and defaults | `submit`: `diarization`, `asr`, `itn`, `redact`; `get_result`: `save_result`; `transcribe`: those options plus `poll_interval=2`, `timeout_seconds=300`, `on_progress`, and `save_result`. `max_retries` is ignored. |
| Input | Batch `AudioInput` accepts bytes-like values, `Path` or string paths, buffered readers, and `BytesIO`. |
`transcribe()` succeeds on `done`, raises on `failed`, and keeps polling
`queued`, `processing`, or `cleared` until its deadline. If your worker owns the
polling loop, stop explicitly on all three terminal states: `done`, `failed`,
and `cleared`.
The default `save_result=False` can clear a `done` or `failed` result after the
response is built. Pass `save_result=True` before polling when terminal
delivery must survive a lost response. This does not establish a result
retention duration.
Use the client as an async or regular context manager. Context exit closes the
internal `aiohttp` session. Batch result and subtitle types are indexed in the
reference sections below.
## Choose another task
| Input and goal | Client | Completion signal |
|---|---|---|
| Complete recording, long meeting, podcast, interview, or archive media | `BatchTranscribeClient` | Job reaches `done`, `failed`, or `cleared` |
| Complete latency-sensitive audio unit, such as one conversational turn for an AI agent | `FastTranscriptionClient` | Final response has `is_final=True` |
| Audio still arriving from a microphone, call, or live source | `RealtimeClient` | Protocol response has `is_final=True` |
| Live speaker segmentation | `RealtimeDiarizationClient` | Final update arrives or close returns the best-known timeline |
| Text to synthesized speech | `TTSClient` | Audio response has `is_last=True` |
Fast transcription is not the path for long meetings, podcasts, or archive
media. Use Batch for those complete, longer recordings.
## Fast task: transcribe one complete conversational unit
Use `FastTranscriptionClient` after a bounded, latency-sensitive audio unit is
complete, such as one user turn in an AI-agent conversation. It sends the whole
unit over Socket.IO; it does not accept an open-ended microphone stream.
### Released Fast surface
| Surface | `0.18.0` contract |
|---|---|
| Constructor | `FastTranscriptionClient(api_url, api_key, api_path=None, on_connect?, on_file_upload?, on_error?, verbose=False)`; the pre-0.17 `(api_url, api_path, api_key, ...)` order still works with a deprecation warning |
| Async methods | `connect()`, `transcribe()`, `close()` |
| Sync methods | `transcribe_sync()`, `close_sync()`; there is no `connect_sync()` |
| Options and defaults | `transcribe(audio, language, model, …)` accepts `on_response`, `on_file_upload`, `on_error`, `timeout_seconds=60`, `diarization_model`, `itn_model`, and `redact_model`. |
| Input | `bytes` or a buffered reader; a path must be opened or read first. |
This tested program reports upload progress, distinguishes partial and final
text, requires a final result, and writes SRT:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
def handle_response(response: stt.FtTranscribeResponse) -> None:
kind = "final" if response.is_final else "partial"
print(f"{kind}:", response.transcription)
def handle_upload(response: stt.FileUploadedResponse) -> None:
print("uploaded:", response.id)
def handle_error(error: stt.ErrorResponse | None) -> None:
if error is not None:
print("server error:", error.code, error.message)
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "short-call.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "short-call.srt")
async with stt.FastTranscriptionClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
) as client:
result = await client.transcribe(
input_path.read_bytes(),
stt.Language.Ar,
stt.FastTranscriptionModel.BayanAr,
on_response=handle_response,
on_file_upload=handle_upload,
on_error=handle_error,
timeout_seconds=60.0,
)
if result is None:
raise RuntimeError("Fast transcription ended without a final result")
output_path.write_text(
stt.Subtitles.from_response(result).to_srt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
`FileUploadedResponse` identifies the upload. Partial and final callbacks
receive `FtTranscribeResponse`; the returned final response has `is_final=True`
and can produce subtitles. Python defaults to a 60-second request timeout.
SDK `0.18.0` accepts `diarization_model`, `itn_model`, and `redact_model` for
wire compatibility, but the validated public Fast service does not apply them.
Omit them; use Batch when those processing options are required.
After an ambiguous timeout, do not blindly resubmit the audio unit: no
idempotency-key contract is published. Use the client context manager so the
Socket.IO and underlying HTTP resources close on every path.
## Realtime task: transcribe audio as it arrives
Use `RealtimeClient` for microphone, call, or other audio that is still
arriving. Input must be PCM16 little-endian, 16 kHz, mono.
### Released Realtime surface
| Surface | `0.18.0` contract |
|---|---|
| Constructor | `RealtimeClient(api_url, api_key, api_path=None, verbose=False)` |
| Async methods | `connect()`, `start_stream()`, `disconnect()` |
| Sync methods | `start_stream_sync()`; stream `send_sync()`, `close_sync()`, and `stop_sync()` are public, but `connect_sync()` and `disconnect_sync()` are not |
| Start options | `language`, `on_connect`, `on_disconnect`, `on_response`, `on_error`, and `subtitles` |
| Stream | `send()` / `send_sync()`; `close(timeout_seconds=1)` / `close_sync()` sends the terminator and waits; `stop()` / `stop_sync()` removes the stream without that final wait. |
This program sends 3,200-byte chunks, representing 100 ms of the required
audio, and closes the client through its async context manager:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
CHUNK_BYTES = 3_200 # 100 ms of PCM16LE, 16 kHz, mono audio.
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "speech.vtt")
finalized_words: list[stt.WordSegment] = []
server_error: stt.ErrorResponse | None = None
protocol_final_observed = False
def handle_response(response: stt.RtTranscribeResponse) -> None:
nonlocal protocol_final_observed
if response.is_final:
kind = "final"
elif response.is_speech_final:
kind = "speech-final"
else:
kind = "partial"
print(f"{kind}:", response.transcription)
if response.is_final:
protocol_final_observed = True
if response.is_final or response.is_speech_final:
# The current public Realtime contract does not guarantee increasing
# seq values, so collect final words in arrival order instead of
# asking RealtimeSubtitles to deduplicate by id:seq.
finalized_words.extend(response.words)
def handle_error(error: stt.ErrorResponse | None) -> None:
# The released SDK can invoke a stream handler more than once for one
# routed error, so keep this callback idempotent.
nonlocal server_error
server_error = error
client = stt.RealtimeClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
stream = await client.start_stream(
language=stt.Language.ArEn,
on_response=handle_response,
on_error=handle_error,
)
pcm = input_path.read_bytes()
for offset in range(0, len(pcm), CHUNK_BYTES):
await stream.send(pcm[offset : offset + CHUNK_BYTES])
await asyncio.sleep(0.1)
# close() sends the last frame and waits for protocol is_final, a routed
# error, or this timeout. It returns rather than raising on timeout.
await stream.close(timeout_seconds=5.0)
if server_error is not None:
raise RuntimeError(server_error.message or server_error.code or "Realtime stream failed")
if not protocol_final_observed:
raise RuntimeError("Realtime stream ended before protocol is_final")
output_path.write_text(
stt.Subtitles.from_words(finalized_words).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
`RtTranscribeResponse` adds `is_speech_final` to the Fast response fields.
Treat `is_speech_final` as an utterance boundary, replace provisional UI text,
and keep the stream open until protocol-level `is_final`.
`stream.close(timeout_seconds=...)` sends the final frame and returns when its
protocol-final wait expires. Return does not guarantee that `is_final` arrived;
`is_speech_final` does not release the wait. The fixture collects final-event
words in arrival order and renders
them with `Subtitles`; it does not rely on `seq`, whose ordering and uniqueness
are not part of the current public wire contract. `RealtimeSubtitles`
deduplicates by `id:seq` and can collapse distinct final events. The client
context remains required because a routed error can remove the stream context
before close runs.
## Diarization task: track speakers live
Use `RealtimeDiarizationClient` when the app needs a speaker timeline while
audio is arriving. Feed and consume concurrently; waiting to consume until all
audio has been sent can stall the workflow.
### Released diarization surface
| Surface | `0.18.0` contract |
|---|---|
| Constructor | `RealtimeDiarizationClient(api_url, api_key, api_path=None, verbose=False)` |
| Async methods | `connect()`, `start_stream()`, `disconnect()` |
| Sync methods | `start_stream_sync()`; stream `send_sync()` and `close_sync()` are public, but `connect_sync()` and `disconnect_sync()` are not |
| Start options | `language=Language.Ar`, plus connection, update, and error callbacks |
| Stream | `stream_id`, `speakers`, `send()` / `send_sync()`, `close(timeout_seconds=5)` / `close_sync()`, async context management, and one async iterator. Iterator failure raises `DiarizationStreamError`. |
`DIARIZATION_RECOMMENDED_CHUNK_BYTES` is imported from
`humain_voice.stt.constants`, not the top-level `stt` namespace. This program
receives updates through `on_update` while it feeds audio, so a close timeout
cannot leave an iterator waiting:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.constants import DIARIZATION_RECOMMENDED_CHUNK_BYTES
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.rttm")
client = stt.RealtimeDiarizationClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
final_observed = False
def on_update(update: stt.DiarizationUpdate) -> None:
nonlocal final_observed
final_observed = final_observed or update.is_final
for segment in update.newly_finalized:
print(segment.speaker, segment.start_time, segment.end_time)
stream = await client.start_stream(
on_update=on_update,
on_error=lambda error: print("server error:", error),
)
pcm = input_path.read_bytes()
if not pcm or len(pcm) % 2:
raise ValueError("Input must be nonempty PCM16 with an even byte length")
for offset in range(0, len(pcm), DIARIZATION_RECOMMENDED_CHUNK_BYTES):
await stream.send(
pcm[offset : offset + DIARIZATION_RECOMMENDED_CHUNK_BYTES]
)
await asyncio.sleep(0.48)
# close() returns the best-known reconciled timeline after five seconds,
# even when no is_final update arrived. A callback avoids leaving an async
# iterator waiting forever on that timeout path.
timeline = await stream.close(timeout_seconds=5.0)
destination = output_path if final_observed else Path(f"{output_path}.partial")
destination.write_text(stt.to_rttm(timeline, uri="meeting"), encoding="utf-8")
if not final_observed:
print(f"Final result not observed; wrote incomplete output to {destination}")
if __name__ == "__main__":
asyncio.run(main())
```
Each `DiarizationUpdate` exposes the full reconciled `segments` timeline,
`newly_finalized`, `active_segments`, and the raw response. Close waits up to 5
seconds for a final update and returns the best-known timeline when that wait
expires. The fixture writes a `.partial` RTTM file unless `is_final` was
observed. Context exit still owns client cleanup.
## TTS task: write a playable WAV file
Use `TTSClient` to discover a voice and synthesize raw audio. Python voice
listing and synthesis have no timeout unless you supply `timeout_seconds`.
`list_voices()` returns multilingual `{ id, label, profile }` dictionaries. The
profile contains shared `speaker` metadata and an open-ended `languages` list;
pass its `id` as `voice_id`.
For the current Arabic/English profiles, any Arabic-script letter in `text`
selects Arabic; otherwise English is selected. Physical variant IDs are
internal and rejected.
### Released TTS surface
| Surface | `0.18.0` contract |
|---|---|
| Constructor | `TTSClient(api_url, api_key, api_path=None, verbose=False, on_connect?, on_error?)`; the pre-0.17 `(api_url, api_path, api_key, ...)` order still works with a deprecation warning |
| Async methods | `connect()`, `list_voices()`, `synthesize()`, `synthesize_stream()`, `close()` |
| Sync methods | `list_voices_sync()`, `synthesize_sync()`, `close_sync()`; there is no `synthesize_stream_sync()`, `connect_sync()`, or `disconnect_sync()` |
| Options and defaults | Synthesis requires text containing at least one Unicode letter or number after trimming and exactly one of `voice_id` or non-empty `voice_references`; `model=TtsModel.Nebula`; optional `timeout_seconds`, `on_audio` for buffered synthesis, `on_error`, and `request_id`. |
| Result | `list_voices()` returns dictionaries with `id`, `label`, and optional `profile`; synthesis responses contain `id`, `is_last`, and `audio: bytes`. |
This program rejects an empty voice list, applies explicit timeouts, and wraps
the returned PCM in a WAV header:
```python
from __future__ import annotations
import asyncio
import os
import sys
import wave
from pathlib import Path
from humain_voice import stt, tts
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
def write_pcm16_wav(path: Path, pcm: bytes, sample_rate: int) -> None:
with wave.open(str(path), "wb") as wav_file:
wav_file.setnchannels(1)
wav_file.setsampwidth(2)
wav_file.setframerate(sample_rate)
wav_file.writeframes(pcm)
def handle_error(error: stt.ErrorResponse | None) -> None:
if error is not None:
print("server error:", error.code, error.message)
async def main() -> None:
output_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.wav")
async with tts.TTSClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
) as client:
voices = await client.list_voices(timeout_seconds=5.0)
if not voices:
raise RuntimeError("No TTS voices are available")
voice = next((item for item in voices if item.get("profile")), voices[0])
if profile := voice.get("profile"):
print(
"profile:",
voice["label"],
profile["speaker"]["dialect"],
profile["languages"],
)
model = tts.TtsModel.Nebula
pcm = await client.synthesize(
"Hello from HUMAIN Voice",
voice_id=voice["id"],
model=model,
# This is an inactivity timeout applied while awaiting each chunk.
timeout_seconds=30.0,
on_error=handle_error,
)
write_pcm16_wav(output_path, pcm, tts.get_sample_rate(model))
if __name__ == "__main__":
asyncio.run(main())
```
Socket.IO TTS returns raw PCM16 little-endian, 24 kHz, mono bytes. The fixture
uses the standard-library `wave` module to write the matching container. Use
`synthesize_stream()` when the app should process each audio chunk.
For `voice_references`, send one reference whose `audio` is standard-base64
RIFF/WAVE containing non-empty mono PCM16 data.
The service independently enforces a non-resetting 25-second overall synthesis
deadline and a 60-second inactivity watchdog. If the overall deadline wins,
`TTS_DEADLINE_EXCEEDED` is retryable and any audio already received is partial.
The `on_error` callback receives a normalized `ErrorResponse`: structured
payloads retain `code` and `retryable`, while a legacy non-object payload
becomes a message. A rejected synthesis coroutine raises a generic message-only
`RuntimeError`, so preserve callback details before cleanup. Always close the
client with a context manager.
## Retry task: read a preserved Batch result
SDK `0.18.0` makes one HTTP call per Batch operation. `max_retries` is
deprecated and ignored. This fixture sets `save_result=True`, then retries the
preserved result with bounded backoff, the released `status_code` and
`retry_after` attributes, and capacity logging. Without preservation, a lost
terminal response can be followed by `cleared`; no retention duration is
defined even when preservation is enabled.
```python
from __future__ import annotations
import asyncio
import os
import random
import sys
from humain_voice import stt
from humain_voice.stt.batchtranscription import TranscriptionResponse
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def get_result_with_retry(
client: stt.BatchTranscribeClient,
job_id: str,
attempts: int = 5,
) -> TranscriptionResponse:
for attempt in range(1, attempts + 1):
try:
# save_result prevents a terminal read from clearing the stored
# result before a retry. It does not define a retention duration.
return await client.get_result(
job_id, stt.Language.ArEn, save_result=True
)
except stt.BatchTranscribeError as error:
rate_limited = isinstance(error, stt.BatchTranscribeRateLimitError)
retryable = rate_limited or error.retryable is True
print(
{
"status_code": error.status_code,
"code": error.code,
"capacity": error.capacity,
}
)
if not retryable or attempt == attempts:
raise
server_delay = 0
if isinstance(error, stt.BatchTranscribeRateLimitError):
server_delay = error.retry_after or 0
exponential_delay = 0.5 * 2 ** (attempt - 1)
await asyncio.sleep(max(server_delay, exponential_delay) + random.random() * 0.25)
raise RuntimeError("Retry loop exhausted")
async def main() -> None:
if len(sys.argv) < 2:
raise RuntimeError("Pass a batch job ID as the first argument")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
) as client:
result = await get_result_with_retry(client, sys.argv[1])
print(result.status.value, result.results.transcript if result.results else "")
if __name__ == "__main__":
asyncio.run(main())
```
Do not reuse that loop blindly for job creation. If an upload times out, the
app might not know whether a job was created.
## Reference: result and error types
| Type | Released fields and behavior |
|---|---|
| `JobResponse` | `job_id`, `status`; the wire alias remains `jobId` |
| `TranscriptionResponse` | `status`; optional `results`, `api_version`, `version`, `metadata`, `diarization_segments`, `error`, `error_code`; properties `job_id`, `file_duration`, `is_complete`, `is_failed`, `is_pending`; `subtitles()` |
| `FileUploadedResponse` / `FtTranscribeResponse` | Upload: `id`, optional `message`. Fast result: `id`, `seq`, `transcription`, `words`, `is_final`, plus `subtitles()`. |
| `RtTranscribeResponse` | Fast result fields plus `is_speech_final`; the latter marks an utterance boundary, while only `is_final` ends the stream |
| `DiarizationUpdate` | `id`, reconciled `segments`, `newly_finalized`, `active_segments`, `is_final`, `raw` |
| `SpeakerContext` / `VoiceProfile` / `VoiceInfo` | `{ gender, dialect }`; `{ speaker, languages }`; `{ id, label, profile? }`. The current API always supplies `profile`. |
| `VoiceReference` / `TtsAudioResponse` | `{ text, audio }` with base64 audio; `id`, `is_last`, `audio: bytes`. `voice_id` and `voice_references` are mutually exclusive. |
| `ErrorResponse` | Optional `id`, `message`, `code`, `retryable`, `timestamp`, `retry_after_seconds`, `data`, `reason`, and `retry_scope`; legacy non-object Socket.IO errors normalize to a message |
| Batch exceptions | `BatchTranscribeError` exposes `status_code`, `payload`, `code`, `retryable`, `job_id`, `detail`, `timestamp`, `capacity`, `raw_body`; subclasses are `BatchTranscribeAuthError`, `BatchTranscribeTimeoutError` (`elapsed_seconds`), `BatchTranscribeJobFailedError` (`error`, `error_code`), and `BatchTranscribeRateLimitError` (`retry_after`). |
| Socket.IO failure paths | Routed Fast errors call `on_error` then raise a message-only `RuntimeError`; Realtime signals its callback and final wait; diarization iteration raises `DiarizationStreamError`; routed TTS errors keep the callback structured but synthesis raises a message-only `RuntimeError`. An unrouteable error can reach only the global callback, so keep an app deadline and always clean up. |
## Reference: imports and event constants
`BatchDiarization`, `BatchRedact`, Batch `AudioInput`, and Batch response types
are exported from `humain_voice.stt.batchtranscription`, not the top-level
`humain_voice.stt` namespace. `BatchTranscriptionModel` is available through
`stt`.
TTS exports `TtsModel`, `DEFAULT_SAMPLE_RATE`, `MODEL_SAMPLE_RATES`,
`get_sample_rate()`, and `decode_tts_audio_frame()`.
| Import path | Public event constants and wire values |
|---|---|
| `humain_voice.stt.constants` | `EVENT_FT_ERROR="error"`, `EVENT_FT_TRANSCRIBE_FILE="audio_file"`, `EVENT_FT_TRANSCRIBE_FILE_UPLOAD_SUCCESS="audio_file_upload_success"`, `EVENT_FT_TRANSCRIBE_RESULT="transcription_result"` |
| `humain_voice.stt.constants` | `EVENT_RT_AUDIO_STREAM="audio_stream"`, `EVENT_RT_END_AUDIO_STREAM="end_audio_stream"` |
| `humain_voice.stt.constants` | `EVENT_DIARIZATION_STREAM="diarization_stream"`, `EVENT_DIARIZATION_RESULT="diarization_result"` |
| `humain_voice.tts` | `EVENT_TTS_REQUEST="tts"`, `EVENT_TTS_AUDIO="tts_audio"`, `EVENT_TTS_ERROR="error"`, `EVENT_TTS_VOICE_LIST_REQUEST="tts_voice_list"`, `EVENT_TTS_VOICE_LIST_RESULT="tts_voice_list_result"` |
`humain_voice.errors` exports the same uppercase error-code constants listed in
the JavaScript guide. It also exports `is_asr_code()`, `is_tts_code()`,
`is_request_scoped_code()`, `is_realtime_owned()`, `is_tts_owned()`,
`is_diarization_code()`, and `is_diarization_owned()` for structured Socket.IO
error routing. The top-level `humain_voice.stt` namespace does not re-export
the STT event constants.
## Reference: subtitle helpers
| API | `0.18.0` contract |
|---|---|
| `Subtitles` | `SubtitleCue`, `SubtitleOptions`, and `SubtitleError`; constructor and `cues`; `from_words`, `from_cues`, `from_response`; `to_srt`, `to_vtt` |
| `RealtimeSubtitles` | `words`, `cues`, `add_response`, `subtitles`, `to_srt`, `to_vtt`; ignores partials and deduplicates finalized `id:seq` responses |
| Top-level helpers | `words_to_cues`, `cues_to_srt`, `cues_to_vtt`, `subtitles`, `to_srt`, `to_vtt` |
| Shaping defaults | `max_duration_seconds=6`, `max_gap_seconds=0.7`, `min_duration_seconds=0.5`, `max_chars_per_line=42`, `max_lines=2`, `split_on_speaker_change=True`, `strict=False`; SRT `start_index=1` |
Subtitle input accepts Batch word offsets and Realtime word segments. Enable
strict mode when malformed or out-of-order timing must fail instead of being
normalized or skipped.
## Next steps
---
# Fast Transcription
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/asyncapi/fast-transcription
Use Fast transcription for one already-complete, bounded audio unit whose
latency matters, such as a conversational or AI-agent turn. Send the complete
encoded unit once through the binary `audio_file` event and receive result
events through `transcription_result`.
Fast transcription is not live microphone input. Use Batch for long or large
meetings, podcasts, and archives. This contract defines no latency guarantee.
## Limits
Two independent bounds apply to every `audio_file` upload, and they measure
different things.
The encoded media carried by the event must not exceed **64 MiB**
(`67108864` bytes). Exceeding it emits an `error` with code
`PAYLOAD_TOO_LARGE` and `data.bound: fast_audio_bytes`, and then closes the
connection: the transport has already buffered an oversized payload, so the
socket is not left available to repeat it. Note this cap is measured on the
MEDIA BYTES ONLY, after the framing header and the four model-key strings.
The equivalent HTTP route bounds the whole multipart request body with the
same number, so an exactly-64-MiB file passes here but cannot fit inside a
64-MiB HTTP body.
The audio must not DECODE to more than **1800 seconds** (30 minutes).
Exceeding it emits an `error` with code `AUDIO_DURATION_EXCEEDED` and
`data.bound: fast_audio_duration`. This is a separate bound because a small
compressed upload can decode to many hours. Unlike the byte cap this does
NOT close the connection: nothing oversized was buffered, and a client
multiplexing other transcriptions on the same socket keeps them. Both bounds
are inclusive - exactly at the limit succeeds, and only strictly over fails.
Over-long audio is refused before any inference and consumes no
audio-capacity credit. For recordings longer than 30 minutes or larger than
64 MiB, split the audio into shorter units or use the batch transcription
API, whose ceiling is 4 hours per file.
### `audio_file_upload_success` does NOT mean the audio was accepted
It acknowledges that the event was received and passed the checks that can be
made from the bytes alone: framing, the byte cap, and a duration a WAV header
declares for itself. The remaining checks - the container allowlist, the
container's own metadata duration, and the authoritative bounded decode - run
after it, so a compressed upload that decodes to more than 1800 seconds, or a
container outside the accepted set, receives `audio_file_upload_success` and
THEN an `error`. Treat this event as a byte-level receipt, never as admission.
Only an `is_final: true` `transcription_result` means the audio was
transcribed.
## Audio format
The complete payload must be AAC (ADTS), FLAC, MP3, WAV, or an ISO base media
file. The container is identified by the server from the payload itself, not
from a filename or a media type, and anything else is rejected with
`ASR_UNSUPPORTED_CODEC` even when it is otherwise decodable.
The ISO base media entry is a family: MP4 is the intended and supported form,
and MOV, M4A, 3GP, 3G2 and MJ2 share one demuxer with it and are therefore
admitted by the same check. Only MP4 is supported in the sense of being
tested and intended; do not build on the others.
Put the `moov` atom at the FRONT of an ISO base media file. This is not a
policy the server checks and reject on - it is a practical requirement: the
upload is read forward-only, so a trailing `moov` cannot be reached and the
file fails to decode.
Audio is resampled to the sample rate configured for the selected ASR model.
The client does not select that sample rate.
## Multiplexing
Multiple complete units can share one connection. Give every concurrent request
a unique `transcription_id`; do not reuse it until that request reaches a final
result, a routed error, or application-deadline cleanup. Responses echo it as
`id`.
## Language Options
| ID | Code | Description |
|----|------|-------------|
| 0 | `ar` | Arabic |
| 1 | `en` | English |
| 2 | `codeswitch` | Arabic-English code-switching |
| 255 | `auto` | Automatic — resolves to the default configured for the environment, currently the code-switching model |
## 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):**
```js
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):**
```python
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
| Event | Direction | Description |
| --- | --- | --- |
| `audio_file` | Client → Server | Client sends binary audio file for transcription. |
| `audio_file_upload_success` | Server → Client | Server acknowledges receipt of the audio packet; transcription is not complete yet. |
| `transcription_result` | Server → Client | Server streams transcription results. |
| `error` | Server → Client | Server emits error messages. |
## Messages
### Audio file upload (binary)
`audio_file` · Client → Server
Raw binary buffer containing metadata and file bytes.
**Content type:** `application/octet-stream`
Raw unencoded binary buffer. Do not send JSON or base64.
**Byte layout (offsets in bytes):**
| Offset | Size | Field | Description |
|--------|------|-------|-------------|
| 0..15 | 16 | transcription_id | UUID identifying this transcription request |
| 16 | 1 | language_id | Language: 0=Arabic, 1=English, 2=Codeswitch, 255=Auto |
| 17..18 | 2 | asr_model_key length | uint16 LE |
| next N | N | asr_model_key | UTF-8 string (optional; empty to use the language default) |
| next 2 | 2 | dia_model_key length | uint16 LE |
| next N | N | dia_model_key | Reserved in the current public Fast contract; send a zero-length value |
| next 2 | 2 | itn_model_key length | uint16 LE |
| next N | N | itn_model_key | Reserved in the current public Fast contract; send a zero-length value |
| next 2 | 2 | redact_model_key length | uint16 LE |
| next N | N | redact_model_key | Reserved in the current public Fast contract; send a zero-length value |
| remaining | - | file_bytes | Audio file (AAC/FLAC/MP3/MP4/WAV) |
Length fields are little-endian uint16. The example below is an
illustrative hexadecimal layout; spaces and `` are not
transmitted.
### Upload received
`audio_file_upload_success` · Server → Client
Acknowledges receipt of the packet and echoes its request ID. This is not transcription completion.
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | Request ID echoed from the received packet. |
**Examples**
*Packet received*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8"
}
```
### Transcription result
`transcription_result` · Server → Client
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | Request ID echoed from the audio packet. |
| `seq` | integer (int64) | Yes | Sequence value supplied with this result. Ordering and aggregation semantics are not part of the public Fast contract. |
| `transcription` | string | Yes | Transcription text carried by this result event. |
| `words` | WordSegment[] | Yes | Timed words carried by this result event. |
| `is_final` | boolean | Yes | True when this is the terminal result event for the request. |
#### `WordSegment`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `start_time` | number (float) | Yes | Word start time in seconds within the submitted audio unit. |
| `end_time` | number (float) | Yes | Word end time in seconds within the submitted audio unit. |
| `word` | string | Yes | Recognized word text. |
**Examples**
*Non-final result*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "hello wor",
"words": [
{
"start_time": 0,
"end_time": 0.45,
"word": "hello"
}
],
"is_final": false
}
```
*Final result*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "hello world",
"words": [
{
"start_time": 0,
"end_time": 0.45,
"word": "hello"
},
{
"start_time": 0.46,
"end_time": 0.9,
"word": "world"
}
],
"is_final": true
}
```
### Error message
`error` · Server → Client
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | No | Transcription request UUID (present when parseable from payload) |
| `code` | string | Yes | Machine-readable error code. Switch on this value rather than on the message text. |
| `data` | object | No | Present only on limit rejections. Names the bound that was exceeded, its configured value and the observed value, so a client can tell which limit it hit without parsing prose. For `fast_audio_duration` the unit is `seconds`; where the service stopped decoding at the ceiling it never learned the true total length, so `observed` is a MINIMUM. For `fast_audio_bytes` the unit is `bytes` and `observed` is the exact media size. |
| `message` | string | Yes | Human-readable error text (same values as previous bare strings) |
| `retryable` | boolean | Yes | Whether the client should retry |
| `timestamp` | string (date-time) | Yes | Server timestamp for the error event. |
**Examples**
*Invalid data type*
```json
{
"code": "VALIDATION_INVALID_FORMAT",
"message": "Invalid data type",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z"
}
```
*Encoded media exceeds the 64 MiB cap (connection then closes)*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "PAYLOAD_TOO_LARGE",
"message": "audio payload too large",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z",
"data": {
"limit": 67108864,
"observed": 83886080,
"unit": "bytes",
"bound": "fast_audio_bytes"
}
}
```
*Audio decodes to more than 1800 seconds (connection stays open)*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "AUDIO_DURATION_EXCEEDED",
"message": "decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z",
"data": {
"limit": 1800,
"observed": 3601,
"unit": "seconds",
"bound": "fast_audio_duration"
}
}
```
*Container is outside AAC/FLAC/MP3/MP4/WAV*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "ASR_UNSUPPORTED_CODEC",
"message": "audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z"
}
```
---
# Realtime ASR
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/asyncapi/realtime
Realtime here means PCM audio is still arriving while recognition or
diarization runs. Use Fast transcription for one already-complete, bounded,
latency-sensitive conversational or AI-agent unit. Use Batch for long or
large complete meetings, podcasts, recordings, or archives.
This page describes the client-side Socket.IO event contract, so operation
actions are relative to the client. JavaScript and Python SDK `0.18.0` wrap
`audio_stream` and the dedicated `diarization_stream`; the ASR bit-2
diarization tee is a direct-event contract. `speaker_id` is obsolete and
returns `METHOD_NOT_ALLOWED`.
## Audio Format
Audio data is expected to be formatted as:
* PCM16 little endian
* 16 kHz
* mono
Audio payloads must contain an even number of bytes.
## Limits
Four bounds apply to a realtime session. All are inclusive: exactly at the
limit succeeds, and only strictly over it fails.
**Per event: 16 MiB.** One `audio_stream` or `diarization_stream` event must
not exceed `16777216` bytes, counting the 18-byte header. Exceeding it emits
`PAYLOAD_TOO_LARGE` with `data.bound` of `realtime_asr_frame_bytes` or
`realtime_diarization_frame_bytes`, then closes the connection. This matches
the cap the equivalent HTTP routes already enforced.
**Per session, total audio content: 14400 seconds (4 hours).** Accumulated
accepted audio, which is a different quantity from how long the session has
been open. Exceeding it emits `AUDIO_DURATION_EXCEEDED` with
`data.bound: session_audio_duration` and retires the session; start a new one.
**Per session, audio rate: four times real time.** Audio may arrive at up to
`128000` bytes per second, with a burst allowance of 16 MiB - one
maximum-size frame. A client streaming genuinely in real time uses a quarter
of its allowance and can never trip this; a client catching up after a
network stall drains its backlog at three times real time. Exceeding it emits
`SESSION_BYTE_RATE_EXCEEDED` with `data.bound: session_audio_rate_burst` and
`retry_after_seconds` (this transport has no `Retry-After` header, so the wait
travels in the frame), and DOES NOT close the connection: the identical
payload succeeds once credit refills. No credit or quota is consumed by a
rejection.
The bucket's capacity always covers the largest frame a surface accepts, so a
maximum-size frame is never refused by the rate bound on a NEWLY STARTED
session. On Socket.IO the bucket belongs to the CONNECTION and is shared by
every audio event on it, so a maximum-size frame sent on a connection that has
already streamed audio can be throttled; honour `retry_after_seconds` and
resend it unchanged.
The per-session accumulated-byte, wall-clock-duration and idle bounds are
unchanged.
## Credit and billing errors
A realtime ASR stream reserves a renewable credit lease at start and renews
it as it runs. Two funding outcomes are distinct and are reported with the
same codes on every transport and over HTTP:
* `CREDITS_EXHAUSTED` — the account is out of credit. HTTP 402;
`retryable: false` (an immediate replay cannot restore funding).
* `BILLING_AUTHORIZATION_UNAVAILABLE` — the billing authority could not be
reached or gave an undecidable answer, so the request fails closed rather
than serving unpaid work. HTTP 503; `retryable: true` (retry after a wait).
These may arrive at stream START (the reserve was refused) or MID-STREAM (a
lease renewal was denied while audio was still arriving).
**Mid-stream is terminal for the stream.** When a renewal is denied the
server stops accepting new billable audio, ALWAYS sends the terminal `error`
event FIRST, then closes. Already-accepted audio up to that point is billed;
nothing after the terminal event is accepted. A start-time reserve refusal is
NOT terminal — the socket multiplexes other operations, so that error is
emitted without closing.
**Close codes.** On the raw-WebSocket OpenAI-compatible endpoint the close
frame carries a private-use (RFC 6455 §7.4.2, 4000–4999) code encoding
`4000 + HTTP status`: `4402` for `CREDITS_EXHAUSTED`, `4503` for
`BILLING_AUTHORIZATION_UNAVAILABLE`. **This Socket.IO transport carries no
application-level close code** — Socket.IO runs over, but is not, raw
WebSocket and does not surface an RFC 6455 code to the application layer, so
on Socket.IO the terminal JSON `error` event is the authoritative signal and
the disconnect that follows carries no 4000-range code. Treat the `error`
event, not a close code, as the contract on this transport.
## Frame validation
Every frame is validated before any model work. A frame is rejected when it
is shorter than its 18-byte header, when its stream UUID is all zeroes, when
it sets a flag bit outside the three defined below, when its language byte is
not one of `0`, `1`, `2` or `255`, when its audio is empty, or when its audio
length is odd. A truncated frame is answered, never silently accepted. All of
these are client-fixable input faults and none is reported as a server error.
## Realtime ASR buffering
Recommended to send 100ms worth of samples (1600 samples).
* Realtime ASR performs inference on 1600 samples.
* When fewer than 1600 samples are sent, Realtime ASR buffers up to 1600 samples before inference.
* When more than 1600 samples are sent, Realtime ASR segments the audio into 1600-sample chunks.
These buffering rules do not describe the dedicated `diarization_stream`,
which forwards each received audio chunk to the diarization service.
## Multiplexing
Multiple streams can share one connection. The request UUID occupies the
first 16 bytes of every frame and is echoed as response `id`. Reuse it for
one stream and use a fresh UUID for every new stream.
## Language Options (STT)
| ID | Code | Description |
|----|------|-------------|
| 0 | `ar` | Arabic |
| 1 | `en` | English |
| 2 | `codeswitch` | Arabic-English code-switching |
| 255 | `auto` | Automatic — resolves to the default configured for the environment, currently the code-switching model (direct wire; SDK `0.18.0` exposes named values for IDs 0, 1, and 2) |
## 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):**
```js
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):**
```python
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
| Event | Direction | Description |
| --- | --- | --- |
| `audio_stream` | Client → Server | Client sends binary audio stream. |
| `speaker_id` | Client → Server | Obsolete; server returns METHOD_NOT_ALLOWED. |
| `transcription_result` | Server → Client | Server streams transcription results. |
| `speaker_id_result` | Server → Client | Obsolete; no speaker_id_result is emitted. |
| `diarization_stream` | Client → Server | Client sends binary audio for speaker diarization. |
| `diarization_result` | Server → Client | Server streams speaker diarization segments. |
| `error` | Server → Client | Server emits error messages. |
## Messages
### Audio stream packet
`audio_stream` · Client → Server
Raw binary buffer containing stream metadata and audio bytes.
**Content type:** `application/octet-stream`
Raw unencoded binary buffer. Do not send JSON or base64.
Byte layout (offsets in bytes):
- 0..15: transcription_id (UUID, 16 bytes)
- 16: flags (uint8)
- bit 0: is_start (start of stream)
- bit 1: is_final (end of stream)
- bit 2: diarization_enabled (tee audio to diarization service;
results arrive as `diarization_result` events)
- bits 3-7: reserved (0)
- 17: language_id (uint8)
- 0 = Arabic
- 1 = English
- 2 = Codeswitch
- 255 = Auto
- 18..end: audio bytes (PCM16 LE, 16 kHz, mono; even byte length)
Recommended chunk: 1600 samples (100ms).
A one-frame stream may set both start and final bits (`flags=3`). Bit 2
is a direct-event ASR feature; SDK `0.18.0` does not expose it.
**Examples**
*Start of stream, English*
```text
12ab34cd56ef789012ab34cd56ef7890 01 01
```
*Mid stream, Arabic*
```text
12ab34cd56ef789012ab34cd56ef7890 00 00
```
*Final stream frame*
```text
12ab34cd56ef789012ab34cd56ef7890 02 01
```
### Speaker ID packet
`speaker_id` · Client → Server
Obsolete; requests return METHOD_NOT_ALLOWED.
**Content type:** `application/octet-stream`
Obsolete raw binary speaker ID buffer. The server no longer performs
speaker identification and emits a non-retryable `METHOD_NOT_ALLOWED`
error instead of forwarding audio to a SpeakerID backend.
Byte layout (offsets in bytes):
- 0..15: transcription_id (UUID, 16 bytes)
- 16..end: audio bytes (PCM16 LE, 16 kHz, mono; even byte length)
**Examples**
*Speaker identification request*
```text
12ab34cd56ef789012ab34cd56ef7890
```
### Transcription result
`transcription_result` · Server → Client
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | Stream UUID echoed from the input frame. |
| `seq` | integer (int64) | Yes | Sequence value supplied with this result. Ordering and uniqueness are not part of the current public Realtime contract. |
| `transcription` | string | Yes | Transcription text carried by this result event. |
| `words` | WordSegment[] | Yes | Timed words carried by this result event. |
| `is_final` | boolean | Yes | True when this is the terminal result for the stream. |
| `is_speech_final` | boolean | Yes | True at an end-of-speech boundary; the stream can continue unless is_final is also true. |
#### `WordSegment`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `start_time` | number (float) | Yes | Word start time in seconds. |
| `end_time` | number (float) | Yes | Word end time in seconds. |
| `word` | string | Yes | Recognized word text. |
**Examples**
*Non-final result*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "hello wor",
"words": [
{
"start_time": 0,
"end_time": 0.45,
"word": "hello"
}
],
"is_final": false,
"is_speech_final": false
}
```
*Final result*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "hello world",
"words": [
{
"start_time": 0,
"end_time": 0.45,
"word": "hello"
},
{
"start_time": 0.46,
"end_time": 0.9,
"word": "world"
}
],
"is_final": true,
"is_speech_final": true
}
```
### Speaker ID result
`speaker_id_result` · Server → Client
Obsolete; this message is no longer emitted.
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | Obsolete speaker ID request UUID. |
| `speaker` | string | Yes | Obsolete server-provided speaker identifier. |
**Examples**
*speaker*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"speaker": "speaker-1"
}
```
### Diarization audio stream packet
`diarization_stream` · Client → Server
Raw binary buffer for speaker diarization. It uses the same 18-byte
envelope as `audio_stream`, with dedicated flag semantics. The
diarization model is resolved by the server.
**Content type:** `application/octet-stream`
Raw unencoded binary buffer for the dedicated `diarization_stream`.
Byte layout (offsets in bytes):
- 0..15: stream UUID (16 bytes; reuse for every frame in this stream)
- 16: flags (uint8)
- bit 0: is_start (start of stream)
- bit 1: is_final (end of stream)
- bits 2-7: reserved (send as 0)
- 17: framing-only language slot (ignored by diarization; send 0)
- 18..end: audio bytes (PCM16 LE, 16 kHz, mono; even byte length)
A one-frame stream may set both start and final bits (`flags=3`).
**Examples**
*Start of diarization stream*
```text
12ab34cd56ef789012ab34cd56ef7890 01 01
```
*Final chunk of diarization stream*
```text
12ab34cd56ef789012ab34cd56ef7890 02 00
```
### Diarization result
`diarization_result` · Server → Client
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | Diarization request identifier. |
| `final_segments` | SpeakerSegment[] | Yes | Closed speaker segments that will not change. |
| `active_segments` | SpeakerSegment[] | Yes | Evolving speaker segments that may be updated or promoted. |
| `is_final` | boolean | Yes | True when this is the last response for this diarization stream. |
#### `SpeakerSegment`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `start_time` | number (float) | Yes | Segment start time in seconds. |
| `end_time` | number (float) | Yes | Segment end time in seconds. |
| `speaker` | string | Yes | Speaker label (e.g. SPEAKER_01). |
**Examples**
*Incremental result with finalized and active segments*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"final_segments": [
{
"start_time": 0,
"end_time": 1.5,
"speaker": "SPEAKER_01"
},
{
"start_time": 1.5,
"end_time": 3,
"speaker": "SPEAKER_02"
}
],
"active_segments": [
{
"start_time": 3,
"end_time": 4.2,
"speaker": "SPEAKER_01"
}
],
"is_final": false
}
```
*Final result — all segments finalized*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"final_segments": [
{
"start_time": 3,
"end_time": 4.5,
"speaker": "SPEAKER_01"
}
],
"active_segments": [],
"is_final": true
}
```
### Error message
`error` · Server → Client
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | No | Request or stream UUID (present when parseable from the payload) |
| `code` | string | Yes | Machine-readable error code. Switch on this value rather than on the message text. |
| `message` | string | Yes | Human-readable error text (same values as previous bare strings) |
| `retryable` | boolean | Yes | Whether the client should retry |
| `timestamp` | string (date-time) | Yes | Server timestamp for the error event. |
| `retry_after_seconds` | integer | No | Seconds 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. |
| `reason` | string | No | Present only on ASR_STREAM_EXPIRED (SAU-2300). Distinguishes why the realtime ASR stream was ended: `audio_inactivity` (no client audio was forwarded before the idle budget elapsed) or `backend_sequence_lost` (the backend had already evicted the sequence). |
| `retry_scope` | string | No | Present only on ASR_STREAM_EXPIRED (SAU-2300). How to recover: `new_stream` means open a fresh stream (do not replay on the retired id). |
| `data` | object | No | Present only on limit rejections. Names the bound that was exceeded, its configured value and the observed value. |
**Examples**
*Invalid data type*
```json
{
"code": "VALIDATION_INVALID_FORMAT",
"message": "Invalid data type",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z"
}
```
*The account already has as many concurrent realtime ASR streams 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.*
```json
{
"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": 8,
"observed": 8,
"unit": "operations",
"bound": "account_concurrency_realtime_asr"
}
}
```
*The account ran out of credit while a realtime ASR stream was still running. This is TERMINAL: it is the last event on the stream and the server disconnects immediately after it. Audio accepted before this point is billed; nothing after it is accepted. NOT retryable — an immediate replay cannot restore funding. On this Socket.IO transport the disconnect carries no application-level close code, so this `error` event is the authoritative signal (the raw-WebSocket endpoint additionally closes with code 4402).*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "CREDITS_EXHAUSTED",
"message": "insufficient credits",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}
```
*A lease renewal could not be authorized mid-stream because the billing authority was unreachable or gave an undecidable answer, so the stream fails closed rather than serving unpaid work. TERMINAL (last event, then disconnect). Retryable after a wait — start a new stream. On the raw-WebSocket endpoint the close code is 4503; on Socket.IO this event is the authoritative signal.*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "BILLING_AUTHORIZATION_UNAVAILABLE",
"message": "billing authorization unavailable",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z"
}
```
---
# Text-to-Speech
Locale: en
Source: https://docs.voice.humain.com/en/api-guides/asyncapi/tts
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: `tts` → `tts_audio` (binary chunks)
- Voice profile discovery: `tts_voice_list` → `tts_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):**
```js
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):**
```python
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
| Event | Direction | Description |
| --- | --- | --- |
| `tts` | Client → Server | Client sends JSON TTS request. |
| `tts_audio` | Server → Client | Server streams TTS audio as binary chunks. |
| `tts_voice_list` | Client → Server | Client requests available TTS voices. |
| `tts_voice_list_result` | Server → Client | Server returns available TTS voices. |
| `error` | Server → Client | Server emits error messages. |
## Messages
### TTS request
`tts` · Client → Server
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | Yes | Unique identifier for this TTS request (echoed in responses). |
| `text` | string | Yes | Text 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. |
| `model` | string | No | TTS 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_id` | string (uuid) | No | Optional 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_references` | TTSVoiceReference[] \| null | No | Optional 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`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `audio` | string | Yes | Standard-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. |
| `text` | string | Yes | Transcript 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*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"text": "Hello from HUMAIN Voice",
"model": "nebula"
}
```
*TTS request with a specific voice profile*
```json
{
"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*
```json
{
"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
`` are not transmitted.
**Examples**
*Non-final audio chunk*
```text
12ab34cd56ef789012ab34cd56ef7890 00
```
*Final audio chunk*
```text
12ab34cd56ef789012ab34cd56ef7890 01
```
### TTS voice list request
`tts_voice_list` · Client → Server
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
**Examples**
*Request all available voices*
```json
{}
```
### 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*
```json
[
{
"id": "af52a907-1086-46f7-8f5d-72317875d7bd",
"label": "mul_youssef",
"profile": {
"speaker": {
"gender": "male",
"dialect": "arz"
},
"languages": [
"ar",
"en"
]
}
}
]
```
*No voices returned*
```json
[]
```
### Error message
`error` · Server → Client
**Content type:** `application/json`
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string (uuid) | No | TTS request UUID (present when parseable from the payload) |
| `code` | string | Yes | Machine-readable error code |
| `message` | string | Yes | Human-readable error text |
| `retryable` | boolean | Yes | Whether the client should retry |
| `timestamp` | string (date-time) | Yes | UTC RFC 3339 timestamp created when the error is emitted. |
| `retry_after_seconds` | integer | No | Seconds 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. |
| `data` | object | No | Present only on limit rejections. Names the bound that was exceeded, its configured value and the observed value. |
**Examples**
*Invalid JSON payload*
```json
{
"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.*
```json
{
"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*
```json
{
"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)*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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*
```json
{
"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)*
```json
{
"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)*
```json
{
"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)*
```json
{
"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)*
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "SERVER_DEPENDENCY_FAILURE",
"message": "voice resolution is temporarily unavailable",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z"
}
```
---
# المصادقة
Locale: ar
Source: https://docs.voice.humain.com/ar/authentication
استخدم مسار الوصول المعتمد في مؤسستك للحصول على مفتاح API وقيم الاتصال
المهيأة لبيئتك.
## قبل أن تبدأ
جهّز هذه المتطلبات:
| المتطلب | الغرض |
|---|---|
| وقت تشغيل موثوق على الخادم | يُبقي مفتاح API خارج شيفرة المتصفح وتطبيق الجوال |
| `curl` | ينفذ طلب التشخيص غير المعدّل للحالة أدناه |
| مسار الوصول في مؤسستك | يوفر قيم الاتصال وبيان الاعتماد المهيأة |
## احصل على بيانات الاعتماد
احصل على القيم التالية وهيئها عبر مسار الوصول المعتمد في مؤسستك:
- `API_KEY`: الاعتماد الخاص بالعمليات المحمية، مع قدرات الكلام التي يحتاجها
تكاملك.
- `API_URL`: عنوان الخدمة المخصص للبيئة.
- `API_PATH`: تجاوز اختياري لمسار Socket.IO. يستخدم SDK المنشور `/socket.io`
افتراضيًا؛ ولم تُوحّد نقطة النهاية القديمة `sautech.humain.com` بعد، ولذلك
ما زالت تتطلب `/realtime/socket.io`.
لا تخمّن عنوانًا أو مسارًا من بيئة أخرى. استخدم فقط القيم المهيأة للبيئة التي
يعمل فيها التكامل.
## خزّن بيانات الاعتماد
في جلسة Bash محلية، اضبط القيم غير السرية واقرأ المفتاح من دون إظهاره أو وضعه
في سجل أوامر الصدفة:
```bash
export API_URL="https://api.voice.humain.com"
read -rsp "HUMAIN Voice API key: " API_KEY
export API_KEY
printf '\n'
```
في الخدمة المنشورة، مرّر `API_KEY` من مدير أسرار أو متغير بيئة محمي. لا تضعه
في التحكم بالمصدر أو متغيرات البيئة المكشوفة للعميل أو عناوين URL أو السجلات أو
لقطات الشاشة أو رسائل الدعم. لا تطبع المتغير لتتأكد من ضبطه.
اضبط `API_PATH` فقط عندما يتجاوز نشرك القيمة الافتراضية `/socket.io` في SDK.
تتطلب نقطة النهاية القديمة `sautech.humain.com` المسار
`/realtime/socket.io`. لا يستخدمه Batch REST.
## أرسل Origin في Socket.IO
تتطلب مصافحة Socket.IO ترويسة `Origin` حتى من العملاء غير المتصفحين الذين لا
يضبطونها تلقائيًا. أرسل مخطط ومضيف عنوان الخدمة المخصص لبيئتك.
يشتق SDK `0.18.0` ترويسة `Origin` من `api_url` ويضبطها في مصافحة Socket.IO.
أما عميل Socket.IO المباشر فعليه إرسال الترويسة بنفسه مضبوطة على مخطط
`API_URL` ومضيفه. تتطلب عمليات Batch REST وRealtime HTTP ترويسة `x-api-key`؛
ولا يتطلب عقد OpenAPI المنشور لها `Origin`.
## شغّل تشخيصًا غير معدّل للحالة
افحص المسار وبيانات الاعتماد المهيأة من دون رفع صوت أو فتح تدفق.
### اقرأ معرّف عمل Batch غير موجود عمدًا
اقرأ معرّف مهمة صحيح البنية وغير مرتبط بمهمة حقيقية:
```bash
curl -sS -i \
"$API_URL/v1/transcribe/00000000-0000-4000-8000-000000000000" \
-H "x-api-key: $API_KEY"
```
لا يرفع هذا الطلب صوتًا ولا ينشئ مهمة. سجل الحالة والجسم كدليل تشخيصي من مسار
الطلب المهيأ. لا يضمن العقد العام ترتيب التحقق من المصادقة والتفويض والبحث عن
العمل، لذلك لا يثبت `404` وحده صلاحية بيانات الاعتماد وقدرة Batch. تعامل مع
`401` و`403` وفق الإجراءات التصحيحية أدناه.
تجنب `curl -v` في الطرفيات أو السجلات المشتركة، لأن المخرجات التفصيلية للطلب
تتضمن ترويسة `x-api-key`.
## أرسل بيانات الاعتماد
### عمليات HTTP
أرسل `x-api-key` في كل طلب محمي عبر Batch REST أو Realtime HTTP:
```bash
curl -X POST "$API_URL/v1/transcribe/codeswitch?asr=bayan_cs_ar_en" \
-H "x-api-key: $API_KEY" \
-F "file=@meeting.wav"
```
تتطلب كل عملية منشورة حاليًا عبر Batch REST وRealtime HTTP ترويسة
`x-api-key`.
### اتصالات Socket.IO
من وقت تشغيل Node.js أو Bun موثوق، أرسل الترويستين أثناء مصافحة Socket.IO
واستخدم المسار المخصص:
```ts
import { io } from "socket.io-client";
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!,
},
});
```
يضبط عملاء SDK المنشورون هذه المصافحة من `api_url` و`api_key`؛ ويكون
`api_path` اختياريًا وافتراضيًا `/socket.io`. ويشتقون `Origin` من `api_url`
المهيأ. فضّلهم إلا إذا كنت تحتاج إلى التحكم المباشر بالبروتوكول.
## عالج بيانات الاعتماد المرفوضة
تفرع وفق حالة HTTP أولًا. حلّل الرمز `code` القابل للمعالجة آليًا عندما تحتوي
الاستجابة خطأ منصة منظمًا، واحتفظ باستجابة البوابة أو المصادقة غير المنظمة
للتشخيص. لا تتفرع بناءً على نص الرسالة.
| الإشارة | المعنى | الإجراء |
|---|---|---|
| `401`، مع `AUTH_UNAUTHORIZED` أو من دونه | المفتاح مفقود أو فارغ أو غير صالح لمسار الطلب. | تأكد من أن وقت التشغيل الموثوق استقبل القيمة المهيأة وأرسل `x-api-key` من دون طباعتها. إذا كان ينبغي أن يعمل الإعداد، فاتبع مسار الوصول المعتمد في مؤسستك للحصول على بيان اعتماد مصحح. لا تعد محاولة الطلب من دون تغيير. |
| `403` مع `AUTH_FORBIDDEN` | رُفض الوصول إلى العملية المطلوبة. | تأكد من أنك تستدعي الخدمة المقصودة، ثم استخدم مسار الوصول المعتمد في مؤسستك لمعالجة القدرة المطلوبة. لا تعد المحاولة حتى تتغير بيانات الاعتماد أو إمكانية الوصول أو العملية. |
| استجابة `403` أخرى | رفضت بوابة أو طبقة وسيطة أخرى الطلب. | احتفظ بالاستجابة ومعرّف الدعم إن وجد، ثم تحقق من العنوان والمسار وبيانات الاعتماد عبر مسار الوصول المعتمد. |
قد يرفض Socket.IO الاتصال أو يصدر حدث `error` بحسب وقت فشل التحقق. أوقف إرسال
الصوت، وافحص قيم البيئة والقدرة نفسيهما، ثم أعد الاتصال فقط بعد تصحيح الإعداد.
## تعامل مع مفتاح مكشوف أو غير مستخدم
إذا ظهر المفتاح في التحكم بالمصدر أو شيفرة العميل أو عنوان URL أو سجل أو موقع
آخر غير موثوق، فاعتبره مكشوفًا:
1. أوقف استخدام المفتاح واحذفه من الإعداد الفعال والمواقع المكشوفة. حذف نسخة
ظاهرة واحدة لا يجعل المفتاح آمنًا من جديد.
2. أبلغ عن التعرض عبر مسار الوصول المعتمد في مؤسستك من دون تضمين بيان الاعتماد
في البلاغ، واتبع تعليمات الاستجابة المقدمة هناك.
3. إذا صدر بديل، فحدّث السر على الخادم وأعد تشغيل أو نشر كل وقت تشغيل موثوق
استخدم القيمة القديمة.
4. احذف النسخ القديمة من مخازن الأسرار وإعدادات النشر، ثم اختبر عملية ممثلة
باستخدام الإعداد الفعال.
للمفتاح غير المستخدم، أوقف استخدامه واتبع مسار الوصول المعتمد نفسه لإجراء
الإيقاف المتبع في مؤسستك.
## الخطوات التالية
بعد أن ينتج التشخيص الاستجابة المتوقعة للبيئة المهيأة، أكمل أول عملية نسخ عبر
البدء السريع لـ SDK أو راجع سلوك وسائل النقل المباشرة.
---
# المفاهيم
Locale: ar
Source: https://docs.voice.humain.com/ar/concepts
ابدأ بسؤالين: هل الإدخال صوت أم نص؟ وإذا كان صوتًا، فهل الوحدة كاملة متاحة
بالفعل؟ تحدد الإجابتان نموذج المعالجة. تأتي وسيلة النقل وعميل SDK بعد ذلك.
## اختر نموذج المعالجة
| نقطة البداية | اختر | السلوك | الحد الفاصل للقرار |
|---|---|---|---|
| تسجيل طويل أو كبير مكتمل | **النسخ الدفعي** | ارفع مرة واحدة، واستلم `jobId`، ثم استعلم عن عمل | استخدمه للاجتماعات والبودكاست والأرشيفات وغيرها عندما يكون الاكتمال غير المتزامن مقبولاً. |
| وحدة صوت مكتملة يهم كمونها | **النسخ السريع** | أرسل وحدة الصوت المشفرة كاملة عبر Socket.IO، ثم استلم أحداث النتائج | استخدمه لعمل كامل الصوت ومحدود النطاق، مثل دور واحد لوكيل أو محادثة. وهو ليس بث صوت مباشر ولا مسار التسجيلات الطويلة. |
| صوت لا يزال يصل | **النسخ الفوري** | أرسل مقاطع PCM16 واستلم نصًا مؤقتًا ونهائيًا ما دام البث مفتوحًا | استخدمه للمكالمات والترجمات والميكروفونات وخطوط الوسائط المباشرة. |
| حاجة إلى معرفة من تكلم ومتى | **تمييز المتحدثين** | أنشئ مقاطع زمنية للمتحدثين إلى جانب صوت Batch أو من بث PCM مباشر | أضفه إلى مسار Batch أو Live المطابق؛ فهو لا ينتج النص المنسوخ بنفسه. |
| نص يجب أن يصبح صوتًا | **تحويل النص إلى كلام (TTS)** | أرسل النص واستلم عينات PCM خام متدفقة | استخدمه عندما يكون الكلام هو الخرج لا الإدخال. |
الحد الحاسم هو حدود الإدخال. يبدأ Batch والنسخ السريع كلاهما بصوت مكتمل؛
ولا تجعل أحداث نتائج Fast الإدخال Realtime. إذا كان الصوت لا يزال يُنتج،
فاختر Realtime.
## Batch عمل
يعيد إرسال Batch القيمة `jobId`. استعلم من مسار النتيجة حتى حالة طرفية أو
حتى انتهاء المهلة الكلية للتطبيق.
| الحالة | النوع | قرار التطبيق |
|---|---|---|
| `queued` | غير طرفية | انتظر ثم استعلم مجددًا ضمن المهلة. |
| `processing` | غير طرفية | استمر في الانتظار ضمن المهلة نفسها. |
| `done` | نجاح طرفي | اقرأ النتيجة المكتملة. |
| `failed` | فشل طرفي | أوقف الاستعلام وأظهر فشل العمل. |
| `cleared` | طرفية بلا نتيجة مخزنة | أوقف الاستعلام وعامل النتيجة على أنها غير متاحة. |
لا تعرّف API المنشورة مدة احتفاظ، لذلك لا تصمم اعتمادًا على نافذة مضمونة
لتوفر النتائج. ينجح SDK `0.18.0` عند `done`، ويرفع خطأ عند `failed`، ويتوقف
فيما عدا ذلك عند مهلته المضبوطة؛ ويجب على المستعلم المباشر معالجة `cleared`
بنفسه.
تستخدم قراءة النتيجة القيمة الافتراضية `save_result=false`. قد تمسح قراءة
`done` أو `failed` النهائية الحقول المخزنة بعد بناء استجابتها، ولذلك قد تتبع
الاستجابة المفقودة حالة `cleared`. اضبط `save_result=true` قبل الاستعلام عندما
يجب أن يكون تسليم النتيجة النهائية قابلاً للتكرار؛ ولا يحدد ذلك مدة احتفاظ.
## نتائج الأحداث حالة وليست سجل نص
تتطور استجابات Fast وRealtime والتمييز. وفّقها حسب معرّف الطلب أو البث بدلاً
من إلحاق كل حدث.
| السطح | علامات النتيجة | قاعدة الحالة |
|---|---|---|
| النسخ السريع | `id`، `seq`، `is_final` | عامل الاستجابات غير النهائية كمؤقتة وثبت الاستجابة النهائية مرة واحدة. |
| النسخ الفوري | `id`، `seq`، `is_final`، `is_speech_final` | استبدل النص المؤقت ما دام علما النهاية false؛ وثبته عندما يصبح أحدهما true. |
| التمييز المباشر | `id`، `final_segments`، `active_segments`، `is_final` | اجمع الإضافات النهائية غير المشاهدة واستبدل الذيل النشط القابل للمراجعة. |
تتضمن استجابات Fast وRealtime القيمة `seq`، لكن عقديهما العامين الحاليين لا
يعرّفان لها دلالات ترتيب أو تفرّد. وجّه الأحداث حسب `id` وعالجها بترتيب الوصول
المرصود، وعامل نص كل حدث وكلماته كحالة ذلك الحدث. لا تنهِ الانتظار إلا عند
إشارة النهاية الخاصة بالقدرة أو خطأ أو مهلة.
يتجاهل `RealtimeSubtitles` الاستجابات المؤقتة عمدًا ويزيل تكرار الاستجابات
النهائية حسب معرّف البث و`seq`. ولأن عقد Realtime السلكي الحالي لا يضمن قيم
`seq` متميزة، فلا تستخدم هذا المساعد لجمع عدة أحداث نهائية. اجمع الكلمات
النهائية بترتيب الوصول المرصود واعرضها باستخدام `Subtitles` بدلًا منه.
أنهِ الإدخال المباشر بإطار النهاية الموثق، وانتظر إلى مهلة التطبيق فقط، ونظف
العميل دائمًا. لا يثبت انتهاء انتظار الإغلاق وصول نتيجة نهائية؛ افحص الحالة
التي سجلتها الاستدعاءات.
## التمييز خط زمني
ينتج التمييز تسميات متحدثين نسبية عبر الزمن، لا هوية حقيقية. تعرض تحديثات SDK
المباشرة الخط الزمني الموفق في `update.segments` والإضافات النهائية الجديدة في
`update.newlyFinalized` / `update.newly_finalized`. ينتظر إغلاق بث SDK مدة تصل
إلى خمس ثوان، ويعيد أفضل خط زمني معروف إذا لم يصل تحديث نهائي خلالها.
في استجابة Batch V2، تكون `final_word_segments` و`diarization_segments`
منفصلة. إذا احتاج التطبيق كلمات منسوبة إلى متحدثين، فاختر قاعدة تداخل ووثقها
بدلاً من افتراض أن كل كلمة تحتوي `speaker` بالفعل.
## عقود الصوت والنقل
| السطح | عقد الصوت | نقل SDK `0.18.0` |
|---|---|---|
| النسخ الدفعي | حاوية ملف صوت مكتملة ومدعومة | REST |
| النسخ السريع | ملف AAC أو FLAC أو MP3 أو MP4 أو WAV كامل واحد | Socket.IO |
| النسخ الفوري والتمييز المباشر | PCM16 little-endian، بتردد 16 kHz وأحادي القناة | Socket.IO |
| TTS عبر SDK | خرج PCM16 خام little-endian، بتردد 24 kHz وأحادي القناة | Socket.IO |
| TTS المباشر عبر HTTP | تسجيل بروتوكول بلا فواصل مع إطارات خدمة نظرية تحمل PCM16 بتردد 16 kHz؛ وليس صوتًا قابلاً للفك عمومًا | لا غلاف SDK عامًا |
PCM الخام ليس حاوية ملف وسائط. يحتاج مشغل معتاد إلى ترويسة WAV بمعدل العينات
المطابق. يمكن للتكاملات المباشرة أيضًا استخدام عمليات Realtime HTTP المتحقق
منها؛ ولا يغلفها عميل SDK عام في `0.18.0`.
## الخطوات التالية
تشرح المفاهيم ما الذي تختاره. تعرّف أدلة SDK سلوك العملاء المنشور، وتجمع
الوصفات مهام كاملة، وتعرّف OpenAPI وAsyncAPI عقود البروتوكول المباشر.
---
# مقدمة
Locale: ar
Source: https://docs.voice.humain.com/ar
تحوّل HUMAIN Voice التسجيلات الكاملة أو الصوت المباشر إلى نص، وتولّد الكلام
من النص. ابدأ هنا لاختيار مسار واحد؛ ويتولى [البدء السريع](/ar/quickstart)
تعليمات التثبيت وأول طلب.
## اختر حسب الصوت والنتيجة
| ما لديك أو ما تحتاجه | استخدم | ابدأ هنا |
|---|---|---|
| اجتماع أو بودكاست أو تسجيل طويل كامل آخر | يرفع **النسخ الدفعي** الملف ويستعلم عن نتيجة نهائية. | [البدء السريع](/ar/quickstart) |
| وحدة صوت كاملة تحتاج نتيجة حساسة للكمون، مثل دور محادثة واحد لوكيل | يرسل **النسخ السريع** الصوت كاملاً عبر Socket.IO. وهو ليس بثًا مباشرًا للميكروفون، وليس مسار التسجيلات الطويلة أو البودكاست. | [دليل SDK](/ar/sdk) |
| صوت لا يزال ينتجه ميكروفون أو مكالمة أو خط وسائط | يبث **النسخ الفوري** PCM16 ويعيد نتائج مؤقتة ونهائية. | [البدء السريع](/ar/quickstart) |
| نص يجب تحويله إلى كلام قابل للتشغيل | يعيد **تحويل النص إلى كلام** PCM16؛ وتكتب الوصفة حاوية WAV. | [وصفة TTS إلى WAV](/ar/recipes/text-to-speech-to-file) |
| وقت تشغيل بلا SDK منشور، أو تحكم على مستوى البروتوكول | تستخدم **API المباشرة** REST أو بث HTTP أو Socket.IO من خلفية موثوقة. | [أدلة API](/ar/api-guides) |
إذا كان الصوت موجودًا بالفعل ولم تكن متأكدًا، فاختر Batch. اختر Realtime فقط
عندما يجب وصول النتائج بينما لا يزال الصوت يُنتج.
## قبل أن تبدأ
- تستهدف هذه الوثائق **SDK JavaScript وPython بالإصدار `0.18.0`**.
- احصل على `API_KEY` عبر [مسار الوصول](/ar/authentication) في مؤسستك. يعرض هذا
الموقع `API_URL` المهيأ لبيئته.
- يستخدم عملاء Socket.IO المسار `/socket.io` افتراضيًا؛ مرّر `API_PATH` فقط
عندما يستخدم النشر مسارًا مخصصًا. وتتطلب نقطة النهاية القديمة
`sautech.humain.com` المسار `/realtime/socket.io`. احتفظ بمفتاح API في بيئة
خادم موثوقة.
يغطي [البدء السريع](/ar/quickstart) التثبيت بإصدار مثبت، وإعداد الصوت،
ومتغيرات البيئة، وأول طلبي Batch وRealtime مختبرين.
## من أول طلب إلى الإنتاج
1. أكمل [البدء السريع](/ar/quickstart) لـBatch أو Realtime.
2. استخدم [دليل SDK](/ar/sdk) الخاص باللغة، أو استخدم
[أدلة API](/ar/api-guides) لتكامل مباشر.
3. أضف تسميات المتحدثين أو الترجمات أو خرج TTS قابلاً للتشغيل من
[الوصفات](/ar/recipes).
4. تعامل مع الأخطاء المنظمة والمهل وإعادة المحاولة المحدودة عبر
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
## الوصول القابل للقراءة آليًا
- يسرد [`/llms.txt`](/llms.txt) نقاط دخول الوثائق؛ ويحتوي
[`/llms-full.txt`](/llms-full.txt) حزمة Markdown الكاملة.
- تستخدم صفحات Markdown السردية `/ar/md/`، مثل
[`/ar/md/quickstart`](/ar/md/quickstart).
- تستخدم صفحات مرجع API المولدة `/ar/api-reference/md/`.
---
# النماذج واللغات والأصوات
Locale: ar
Source: https://docs.voice.humain.com/ar/models
اختر مسار المعالجة أولاً. ثم اختر المعاملات التي يعرضها ذلك المسار فقط: تحدد
اللغة الكلام، ويختار نموذج ASR أداة التعرف، وتعدل محددات المعالجة خرج Batch،
وصوت TTS ليس نموذجًا.
## اتخذ الاختيارات بهذا الترتيب
1. اختر **Batch** للتسجيلات الطويلة أو الكبيرة المكتملة، و**Fast** لوحدة صوت
مكتملة حساسة للكمون مثل دور لوكيل، و**Realtime** ما دام الصوت يصل، أو
**TTS** عندما يكون النص هو الإدخال.
2. لتحويل الكلام إلى نص، اختر قيمة `Language` التي تصف الصوت.
3. لنسخ Batch أو Fast، اختر نموذج ASR الخاص بالمسار عندما تتطلبه العملية أو
عندما يثبته تكاملك عمدًا. يختار النسخ Realtime اللغة لا نموذج ASR.
4. أضف محددات معالجة Batch عند الحاجة فقط. وفي TTS، اختر النموذج ثم صوتًا
متاحًا أثناء التشغيل أو مراجع صوت.
| الاختيار | ما الذي يتحكم فيه | ما الذي لا يتحكم فيه |
|---|---|---|
| اللغة | إدخال عربي أو إنجليزي أو تبديل عربي-إنجليزي | تنفيذ أداة التعرف المحددة |
| نموذج ASR | أداة التعرف التي يستخدمها Batch أو Fast | تأطير لغة Realtime أو TTS |
| محدد المعالجة | التمييز أو التنقيح أو ITN في عمل Batch | نموذج ASR نفسه |
| نموذج TTS | محرك توليف الكلام | هوية الصوت |
| الصوت | معرّف صوت مدرج أو مراجع يقدمها المستدعي | محرك TTS |
توثق هذه الجداول الثوابت التي يصدرها SDK JavaScript وPython بالإصدار `0.18.0`.
لا يضمن تصدير ثابت توفير النموذج أو الصوت لكل مفتاح أو بيئة. استخدم الإعداد
الصادر لبيئتك، وتعامل مع عدم توفر النموذج وقائمة الأصوات الفارغة.
## قيم اللغة
يصدر JavaScript وPython أعضاء `Language` نفسها.
| ثابت SDK | قيمة البروتوكول | بايت إطار Realtime | تستخدمه |
|---|---|---|---|
| `Language.Ar` | `ar` | `0` | مسار Batch، وبيانات Fast، وإطارات Realtime |
| `Language.En` | `en` | `1` | مسار Batch، وبيانات Fast، وإطارات Realtime |
| `Language.ArEn` | `codeswitch` | `2` | مسار Batch، وبيانات Fast، وإطارات Realtime |
| — (البروتوكول المباشر فقط) | `auto` | `255` | مسار Batch، وبيانات Fast، وإطارات Realtime |
تختار `auto` الإعداد التلقائي المضبوط للبيئة، وهو يُحل حاليًا إلى نموذج تبديل
اللغات. وهي قيمة على مستوى البروتوكول المباشر: لا يصدّر SDK `0.18.0` ثابتًا
مسمى لها، لذا لا تصلها إلا عبر تكامل مباشر مع OpenAPI أو AsyncAPI. ولحذف اللغة
حيث تسمح العملية بذلك الأثر نفسه.
للعمليات المباشرة عبر HTTP، استخدم قيم اللغة التي تعلنها عملية OpenAPI
المعنية. لا تمرر تعداد نموذج Batch أو Fast إلى
`RealtimeClient.startStream()` / `start_stream()`.
## نماذج ASR لنسخ Batch وFast
يستخدم JavaScript وPython بالإصدار `0.18.0` أسماء الأعضاء وسلاسل البروتوكول
نفسها.
| قيمة البروتوكول | ثابت Batch | ثابت Fast | قيد SDK المنشور |
|---|---|---|---|
| `nida_ar` | `BatchTranscriptionModel.NidaAr` | `FastTranscriptionModel.NidaAr` | نموذج موسوم للعربية |
| `nida_8k_ar` | `BatchTranscriptionModel.NidaArTelephony` | — | مصدر لـBatch فقط في `0.18.0` |
| `bayan_ar` | `BatchTranscriptionModel.BayanAr` | `FastTranscriptionModel.BayanAr` | نموذج موسوم للعربية |
| `bayan_cs_ar_en` | `BatchTranscriptionModel.BayanArEn` | `FastTranscriptionModel.BayanArEn` | اسم مستعار غير مرقم للعربية-الإنجليزية |
| `bayan_cs_ar_en_v1` | `BatchTranscriptionModel.BayanArEnV1` | `FastTranscriptionModel.BayanArEnV1` | إصدار عربي-إنجليزي ثابت |
| `bayan_cs_ar_en_v2` | `BatchTranscriptionModel.BayanArEnV2` | `FastTranscriptionModel.BayanArEnV2` | إصدار عربي-إنجليزي ثابت |
| `fast_en` | `BatchTranscriptionModel.FastEn` | `FastTranscriptionModel.FastEn` | نموذج موسوم للإنجليزية |
يحتوي تعداد التوافق `ASRModel` الأعضاء السبعة كلها، لكن ينبغي للشيفرة الجديدة
استخدام `BatchTranscriptionModel` أو `FastTranscriptionModel` ليصعب التعبير عن
توليفة غير صالحة للمسار. لا يعرّف سطح SDK ترتيب جودة أو كمون بين `NidaAr`
و`BayanAr`؛ اتبع إعداد النموذج الصادر لبيئتك.
### القيم الافتراضية والأسماء المستعارة والتوافق
| الحالة | سلوك `0.18.0` المنشور |
|---|---|
| حذف ASR من Batch | يكون `asr` اختياريًا؛ ويترك الطلب اختيار النموذج للخدمة. |
| ASR في Fast | يتطلب `FastTranscriptionClient.transcribe()` نموذجًا ولغة؛ ويبقى يرسل وحدة صوت مكتملة واحدة. |
| ASR في Realtime | يتطلب `startStream()` / `start_stream()` لغة ولا يملك معامل نموذج ASR. |
| الاسم المستعار العربي-الإنجليزي | استخدم اسم التوافق غير المرقم `BayanArEn`؛ اختر `BayanArEnV1` أو `BayanArEnV2` فقط عند تثبيت قيمة البروتوكول عمدًا. |
| ثابت الاتصال الهاتفي | يغيب `NidaArTelephony` عمدًا عن `FastTranscriptionModel`؛ عامله كقيد توافق في `0.18.0`، لا كتصريح دائم عن توفر المنصة. |
يشترك النسخ السريع مع Batch في اختيار اللغة والنموذج، لا في حدود حمل العمل:
يستهلك Fast وحدة صوت مكتملة حساسة للكمون؛ أما الاجتماعات والبودكاست والأرشيفات
والتسجيلات الطويلة الأخرى فتنتمي إلى Batch.
## محددات معالجة Batch
تعدل المحددات المعالجة؛ ولا تستبدل `Language` أو نموذج ASR.
| الغرض | ثابت SDK أو الخيار | القيمة الصادرة | المعنى |
|---|---|---|---|
| التمييز | `BatchDiarization.Off` | `0` | تعطيل تقسيم المتحدثين |
| التمييز | `BatchDiarization.On` | `1` | تفعيل اختيار التمييز الافتراضي |
| التمييز | `BatchDiarization.D1` | `d1` | اختيار مفتاح التمييز `d1` |
| التمييز | `BatchDiarization.D2` | `d2` | اختيار مفتاح التمييز `d2` |
| التنقيح | `BatchRedact.Off` | `0` | تعطيل التنقيح |
| التنقيح | `BatchRedact.On` | `1` | تفعيل التنقيح |
| ITN | `itn: boolean` | `true` / `false` في طلبات SDK | تبديل التسوية العكسية للنص |
يؤدي حذف المحدد إلى حذف معامل الاستعلام؛ فلا تعرض القيمة المحذوفة كقيمة
افتراضية ثابتة للمعالجة. في REST المباشر، استخدم القيم المقبولة في عملية
OpenAPI الحالية بدلاً من نسخ تسلسل SDK. في Python، يصدر `BatchDiarization`
و`BatchRedact` من `humain_voice.stt.batchtranscription`، لا من مساحة
`humain_voice.stt` العليا.
## نموذج TTS والصوت
| الاختيار | سطح SDK | القيمة أو القاعدة |
|---|---|---|
| النموذج | `TtsModel.Nebula` | قيمة البروتوكول `nebula`؛ وهي قيمة SDK `0.18.0` الافتراضية عند حذف `model`. |
| صوت مدرج | `VoiceInfo` مع `id` و`label` و`profile` | استدعِ `listVoices()` / `list_voices()` ومرر معرّف الهوية المعاد في `voice_id`. |
| مراجع الصوت | `VoiceReference` مع `audio` و`text` | قدم للمسار العام مرجع RIFF/WAVE واحدًا بترميز base64 القياسي، يحوي بيانات PCM16 أحادية غير فارغة ونصها، بدل `voice_id`. |
يتطلب طلب التوليف في SDK `0.18.0` واحدًا بالضبط من `voice_id` أو
`voice_references` غير الفارغة؛ ولا يمثل أي منهما ثابت نموذج. يسمح عقد السلك
المباشر بغياب المحددين، وعندها يكون اختيار الصوت محددًا بالنشر أو النموذج ولا
يضمن صوتًا. تعامل مع قائمة أصوات فارغة بدلاً من تخمين معرّف. تمرر أمثلة
الوثائق مهلة خمس ثوان لقائمة الأصوات في اللغتين؛ لا
تملك Python مهلة افتراضية، بينما تستخدم JavaScript خمس ثوان افتراضيًا لقائمة
الأصوات.
يعيد TTS عبر Socket.IO مع `TtsModel.Nebula` صوت PCM16 خامًا little-endian
بتردد 24 kHz وأحادي القناة. استخدم `getSampleRate()` / `get_sample_rate()`
عند كتابة حاوية.
### هويات الصوت وتسمياته
تحتوي قائمة الأصوات فقط على الهويات السبع متعددة اللغات. يحمل كل عنصر
`profile: { speaker: { gender, dialect }, languages }` ومعرّف هوية ثابتًا، مثل
المعرّف ذي التسمية `mul_youssef`. أرسل ذلك المعرّف في `voice_id`؛ تحتفظ المنصة
بالنسخ الفعلية داخليًا وترفض معرّفاتها عند إرسالها مباشرة.
في هويات العربية/الإنجليزية الحالية، يختار وجود أي حرف من محارف الكتابة
العربية في `text` النسخة العربية؛ وإلا تُختار الإنجليزية. لا تختار العربية
الأرقام أو علامات الترقيم أو الرموز التعبيرية أو المسافات أو حروف الكتابات
غير العربية.
عامل كل `label` بوصفه تلميحًا مقروءًا فقط. اعرض بيانات `profile` المنظمة،
وخزّن `id` الثابت ومرره، ولا تشتق معرّفًا أو تطابقه اعتمادًا على `label`.
## الخطوات التالية
---
# البدء السريع
Locale: ar
Source: https://docs.voice.humain.com/ar/quickstart
أقصر مسار إلى أول نتيجة هو **النسخ الدفعي** لملف صوت مكتمل. فهو يقبل حاوية
صوت مدعومة ولا يتطلب تحضير مقاطع PCM فورية. أكمل هذا المسار أولًا، ثم اختر
التسليم السريع أو الفوري إذا احتاجه منتجك.
## قبل أن تبدأ
جهّز ما يلي قبل تشغيل أي أمر:
- مفتاح API ومسار Socket.IO تحصل عليهما عبر [مسار الوصول](/ar/authentication) في مؤسستك. تعرض
الصفحة عنوان الخدمة المهيأ لبيئتها.
- ملف صوت مكتمل ومدعوم. تستخدم الأمثلة أدناه `meeting.wav` وتكتب التسميات
التوضيحية في `meeting.vtt`.
- إحدى بيئات تشغيل SDK المدعومة:
- JavaScript / TypeScript: بيئة Node.js أو Bun على الخادم تدعم ES2021 و
`fetch` و`FormData` و`Blob`. لا ينشر SDK حدًا أدنى لإصدار Node.js أو Bun.
تُفحص الأمثلة باستخدام Node.js 24 وBun 1.3.14؛ وتفترض أوامر `node`
المباشرة أدناه بيئة التحقق Node.js 24 تلك.
- Python 3.10 أو أحدث.
- `ffmpeg` فقط إذا كنت ستجرب مسار البث الفوري الاختياري.
احتفظ بمفتاح API في إعدادات الخادم. لا تضعه في شيفرة المتصفح أو الجوال.
## 1. ثبّت SDK 0.18.0
اختر لغة واحدة. تستخدم الصفحة تسميات تبويبي JavaScript وPython نفسها في كل
بديل.
JavaScript / TypeScript
Python
```bash
npm install @humain-voice/sdk@0.18.0
```
```bash
python -m pip install humain-voice==0.18.0
```
**النتيجة المتوقعة:** يكمل مدير الحزم بنجاح ويسجل إصدار SDK الدقيق
`0.18.0`.
## 2. اضبط البيئة
شغّل أوامر التصدير هذه في الصدفة نفسها التي ستشغّل المثال. استبدل المفتاح
بالقيمة المهيأة لمؤسستك.
```bash
export API_URL="https://api.voice.humain.com"
export API_PATH="/socket.io"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
test -n "$API_URL" && test -n "$API_PATH" && test -n "$API_KEY" && echo "HUMAIN Voice environment ready"
```
**النتيجة المتوقعة:** يطبع الأمر الأخير `HUMAIN Voice environment ready`.
تنشر هذه البيئة Socket.IO على المسار `/socket.io`. يستخدم كل عميل Socket.IO
في الإصدار `0.18.0` المسار `/socket.io` افتراضيًا.
اضبط `API_PATH` فقط عندما يحتاج النشر إلى مسار مخصص. تتطلب نقطة النهاية
القديمة `sautech.humain.com` المسار `/realtime/socket.io`. يستخدم عميل Batch
القيم `API_URL` و`API_KEY` و`API_VERSION` فقط.
## 3. نفّذ نسخًا دفعيًا
استخدم زر نسخ كتلة الشيفرة واحفظ المثال المحدد باسم الملف المعروض. يرسل
`meeting.wav`، ويستعلم بمهلة خمس دقائق، ويفعّل تمييز المتحدثين، ويطبع النص
المعاد، ويكتب تسميات WebVTT.
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
BatchDiarization,
BatchTranscribeClient,
BatchTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.wav';
const outputPath = process.argv[3] ?? 'meeting.vtt';
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
api_version: process.env.API_VERSION ?? 'v1',
});
try {
const result = await client.transcribe(
await readFile(inputPath),
Language.ArEn,
{
asr: BatchTranscriptionModel.BayanArEn,
diarization: BatchDiarization.On,
saveResult: true,
pollInterval: 2,
timeout: 300,
onProgress: ({ status }) => console.info('status:', status),
},
);
console.info(result.results?.transcript ?? '');
await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.batchtranscription import BatchDiarization
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.vtt")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
api_version=os.environ.get("API_VERSION", "v1"),
) as client:
result = await client.transcribe(
input_path,
lang=stt.Language.ArEn,
asr=stt.BatchTranscriptionModel.BayanArEn,
diarization=BatchDiarization.On,
save_result=True,
poll_interval=2.0,
timeout_seconds=300.0,
on_progress=lambda response: print("status:", response.status.value),
)
print(result.results.transcript if result.results else "")
output_path.write_text(
stt.Subtitles.from_response(result).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
شغّل الأمر المطابق للملف الذي حفظته:
- JavaScript / TypeScript: `node batch-transcription.ts meeting.wav meeting.vtt`
- Python: `python batch_transcription.py meeting.wav meeting.vtt`
**النتيجة المتوقعة:** في العمل الناجح، تطبع الطرفية تحديثًا واحدًا أو أكثر
يبدأ بـ`status:` ثم النص المعاد، ويُنشأ `meeting.vtt`. قد ينتج الصوت الذي لا
يحتوي كلامًا متعرفًا عليه نصًا فارغًا.
يكتمل أول طلب HUMAIN Voice عندما تصل المهمة إلى `done` ويُكتب ملف التسميات.
## بعد النتيجة الأولى
- يستعلم المثال كل ثانيتين مع حد لحلقة الاستعلام قدره 300 ثانية. قد يمدد
الإرسال أو طلب قيد التنفيذ المدة الفعلية. اختر مهلًا تناسب حملك؛ فمهلة الطلب
ليست مهلة سير العمل الإجمالية.
- يعيد SDK `0.18.0` النتيجة عند `done` ويرفع خطأ عند `failed` أو انتهاء
المهلة. لا يتوقف مساعد `transcribe()` بشكل خاص عند `cleared`، فتصل المهمة
الممسوح إلى المهلة المضبوطة. يجب أن يتوقف المستعلم المباشر صراحة عند
`done` و`failed` و`cleared`.
- يغلق المثال العميل حتى عند إخفاق الإرسال أو الاستعلام. حافظ على نمط التنظيف
هذا في الإنتاج.
توسّع [وصفة نسخ تسجيل](/ar/recipes/transcribe-a-recording) أنماط الاستعلام،
وتسميات المتحدثين، والتسميات التوضيحية.
## اختر نمط التسليم التالي
| النمط | استخدمه عندما | تسليم الصوت | تدفق النتيجة |
|---|---|---|---|
| النسخ الدفعي | لديك تسجيل مكتمل، بما في ذلك الاجتماعات أو المكالمات أو حلقات البودكاست الأطول | ارفع مرة واحدة | استعلم عن المهمة حتى `done` أو `failed` أو `cleared` |
| النسخ السريع | تحتاج حمولة صوت مكتملة وقصيرة إلى زمن وصول أقل، مثل دور واحد في محادثة وكيل | أرسل الحمولة المكتملة مرة واحدة عبر Socket.IO | استقبل أحداث الرفع والنسخ حتى النتيجة النهائية |
| النسخ الفوري | ما زال الصوت يصل من ميكروفون أو مكالمة أو مصدر مباشر | أرسل مقاطع PCM16 little-endian بتردد 16 kHz وأحادية القناة | استبدل النص المؤقت حتى تصل استجابة نهائية أو نهاية كلام |
النسخ السريع ليس مسار الصوت الطويل أو البودكاست. استخدم Batch لهذه التسجيلات
المكتملة؛ واستخدم النسخ السريع عندما تكون الحمولة المكتملة قصيرة ويهم زمن
الوصول.
## اختياري: نفّذ نسخًا فوريًا
يجب أن يكون دخل Realtime مسبقًا بصيغة PCM16 little-endian خام، بتردد 16 kHz،
وأحادي القناة. حوّل تسجيلًا لهذا المثال:
```bash
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ar 16000 -ac 1 speech.pcm
```
**النتيجة المتوقعة:** ينتهي `ffmpeg` بنجاح وينشئ `speech.pcm`. لا يملك PCM
الخام ترويسة ملف قابلة للتشغيل.
احفظ المثال المحدد باسم الملف المعروض:
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
type ErrorResponse,
Language,
RealtimeClient,
Subtitles,
type WordSegment,
} from '@humain-voice/sdk';
const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'speech.pcm';
const outputPath = process.argv[3] ?? 'speech.vtt';
const client = new RealtimeClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
const finalizedWords: WordSegment[] = [];
let serverError: ErrorResponse | undefined;
let protocolFinalObserved = false;
try {
const stream = await client.startStream(Language.ArEn, {
onResponse: (response) => {
const kind = response.is_final
? 'final'
: response.is_speech_final
? 'speech-final'
: 'partial';
console.info(`${kind}:`, response.transcription);
if (response.is_final) protocolFinalObserved = true;
if (response.is_final || response.is_speech_final) {
// The current public Realtime contract does not guarantee increasing
// seq values, so collect final words in arrival order instead of
// asking RealtimeSubtitles to deduplicate by id:seq.
finalizedWords.push(...response.words);
}
},
// The released SDK can invoke a stream handler more than once for one
// routed error, so keep this callback idempotent.
onError: (error) => {
serverError = error;
},
});
const pcm = await readFile(inputPath);
for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
await pause(100);
}
// close() sends the last frame and waits for protocol is_final, a routed
// error, or this timeout. It resolves rather than throwing on timeout.
await stream.close(5);
if (serverError) {
throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
}
if (!protocolFinalObserved) {
throw new Error('Realtime stream ended before protocol is_final');
}
await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
CHUNK_BYTES = 3_200 # 100 ms of PCM16LE, 16 kHz, mono audio.
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "speech.vtt")
finalized_words: list[stt.WordSegment] = []
server_error: stt.ErrorResponse | None = None
protocol_final_observed = False
def handle_response(response: stt.RtTranscribeResponse) -> None:
nonlocal protocol_final_observed
if response.is_final:
kind = "final"
elif response.is_speech_final:
kind = "speech-final"
else:
kind = "partial"
print(f"{kind}:", response.transcription)
if response.is_final:
protocol_final_observed = True
if response.is_final or response.is_speech_final:
# The current public Realtime contract does not guarantee increasing
# seq values, so collect final words in arrival order instead of
# asking RealtimeSubtitles to deduplicate by id:seq.
finalized_words.extend(response.words)
def handle_error(error: stt.ErrorResponse | None) -> None:
# The released SDK can invoke a stream handler more than once for one
# routed error, so keep this callback idempotent.
nonlocal server_error
server_error = error
client = stt.RealtimeClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
stream = await client.start_stream(
language=stt.Language.ArEn,
on_response=handle_response,
on_error=handle_error,
)
pcm = input_path.read_bytes()
for offset in range(0, len(pcm), CHUNK_BYTES):
await stream.send(pcm[offset : offset + CHUNK_BYTES])
await asyncio.sleep(0.1)
# close() sends the last frame and waits for protocol is_final, a routed
# error, or this timeout. It returns rather than raising on timeout.
await stream.close(timeout_seconds=5.0)
if server_error is not None:
raise RuntimeError(server_error.message or server_error.code or "Realtime stream failed")
if not protocol_final_observed:
raise RuntimeError("Realtime stream ended before protocol is_final")
output_path.write_text(
stt.Subtitles.from_words(finalized_words).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
شغّل الأمر المطابق للملف الذي حفظته:
- JavaScript / TypeScript: `node realtime-transcription.ts speech.pcm speech.vtt`
- Python: `python realtime_transcription.py speech.pcm speech.vtt`
**النتيجة المتوقعة:** تصف الطرفية الاستجابات بـ`partial:` أو `final:` أو
`speech-final:`، ويكتب التدفق الناجح التسميات النهائية في `speech.vtt`.
بعد النجاح، أبقِ نص واجهة المستخدم المؤقت منفصلًا واستبدله عند وصول أحداث
النتائج. يجمع المثال الكلمات من الأحداث النهائية أو أحداث نهاية الكلام فقط، ثم
يستخدم `Subtitles` لعرضها؛ ولا يعتمد على `seq` لأن ترتيبها ليس جزءًا من عقد
Realtime السلكي الحالي. يغلق المثال التدفق، وينتظر حتى خمس ثوانٍ لوصول
`is_final` على مستوى البروتوكول، ويفصل العميل أثناء التنظيف. ويبلغ انتهاء
المهلة بوصفه عدم اكتمال بدلاً من كتابة ملف تسميات عادي.
## الخطوات التالية
تابع المسار الذي يطابق منتجك. قبل حركة الإنتاج، أعد تشغيله بمدخلات ممثلة
واختبر المهل والحالات النهائية والانقطاعات وإعادة المحاولة والتنظيف مهما كان
نمط التسليم.
---
# استكشاف الأخطاء وإصلاحها
Locale: ar
Source: https://docs.voice.humain.com/ar/troubleshooting
تستهدف هذه الصفحة `@humain-voice/sdk@0.18.0` و
`humain-voice==0.18.0`. شخّص بالاعتماد على الأدلة: التقط الحالة والحدث
والمعرّف والإشارة النهائية قبل تغيير الإعدادات أو إعادة المحاولة.
## شخّص بهذا الترتيب
1. تأكد من أن الحزمة المثبتة هي `0.18.0` بالضبط.
2. تأكد من وجود `API_URL` و`API_KEY` في عملية الخادم.
3. اختر وضع المعالجة وفق الدخل الموجود فعلًا.
4. أعد إنتاج المشكلة بدخل واحد صغير ومعروف وطلب واحد. عطّل إعادات المحاولة
المتزامنة أثناء عزل الإخفاق.
5. سجل حقول الخطأ المنظمة وما إذا اكتمل التنظيف.
شغّل أمر إصدار الحزمة المناسب لتطبيقك فقط. تعرض حلقة الصدفة وجود المتغير من
دون طباعة السر؛ لا تستبدلها بـ`env` أو أمر آخر يكشف `API_KEY`.
```sh
npm ls @humain-voice/sdk --depth=0
python -c 'from importlib.metadata import version; print(version("humain-voice"))'
for name in API_URL API_KEY; do
if [ -n "$(printenv "$name")" ]; then
printf "%s=set\n" "$name"
else
printf "%s=missing\n" "$name"
fi
done
```
## اختر وضع المعالجة الصحيح
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يتعطل اجتماع طويل أو بودكاست أو ملف أرشيفي في النسخ السريع | استُخدم النسخ السريع لمادة طويلة | كان التسجيل كله موجودًا قبل الطلب وهو طويل | استخدم `BatchTranscribeClient` واستعلم ضمن مهلة نهائية محدودة |
| يضيف دور محادثة محدود تعقيد بث لا حاجة إليه | استُخدم Realtime رغم وجود الدور كاملًا | لا يصل صوت بعد بدء الطلب | استخدم `FastTranscriptionClient` للوحدة المكتملة مسبقًا والحساسة لزمن الوصول |
| يُرفع صوت ميكروفون أو مكالمة مرارًا كملفات مكتملة | استُخدم Batch أو الوضع السريع بينما لا يزال الصوت يصل | يجب أن تبدأ المعالجة قبل انتهاء التسجيل | استخدم `RealtimeClient` أو `RealtimeDiarizationClient` وأرسل PCM مؤطرًا عند وصوله |
| يُرسل ملف مكتمل كـPCM مباشر أو يُرفع PCM كملف | حدث خلط بين دخل الحاوية ودخل التدفق | قارن بايتات الدخل بعقد العملية المختارة | أرسل ملفًا مشفرًا إلى Batch أو Fast، وأرسل PCM16 LE بلا ترويسة إلى Realtime |
لا يَعِد اختيار الوضع بزمن وصول معين. بل يختار دورة الحياة وعقد الدخل
المطابقين للمهمة.
## أعراض الاتصال والمصادقة
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يعيد REST `401` أو `403` | المفتاح مفقود أو غير صالح أو لا يملك وصولًا للعملية | سجل حالة HTTP و`code` المنظم، وتأكد فقط من ضبط `API_KEY` | أرسل القيمة المخصصة كـ`x-api-key` أو `api_key`؛ وعالج بيانات الاعتماد غير الصالحة أو المرفوضة عبر مسار الوصول المعتمد في مؤسستك |
| يقول مُنشئ Socket.IO إن الرابط أو المفتاح مطلوب | إحدى قيمتي `api_url` أو `api_key` فارغة | سجل أسماء الخيارات ووجودها، ولا تسجل قيمة المفتاح | مرر `API_URL` و`API_KEY` المخصصين؛ ويكون `api_path` افتراضيًا `/socket.io` |
| يرفع Socket.IO `connect_error` أو لا يستدعي معالج الاتصال | المضيف أو المسار خاطئ، أو ترقية WebSocket محجوبة، أو المصافحة مرفوضة | قارن `API_URL` والمسار الفعلي `/socket.io` بالقيم الصادرة؛ وفي Python أعد الإنتاج مرة مع `verbose=True` واحتفظ بخطأ المصافحة | استخدم المسار الافتراضي ما لم يوثق نشرك تجاوزًا، وأبقِ نقل WebSocket مفعّلًا، واضبط proxy ليحافظ على الترقية |
| يعمل REST لكن تفشل كل قدرات Socket.IO | مسار Socket.IO أو ترقية WebSocket محجوبان | ينجح طلب REST محمي بينما تفشل مصافحة Socket.IO قبل أي حدث تطبيق | اختبر `/socket.io` من شبكة الخادم نفسها؛ واضبط `API_PATH` فقط لتجاوز موثق |
| تُرفض مصافحة Socket.IO قبل أي حدث تطبيق | ترويسة `Origin` المطلوبة مفقودة أو لا تطابق أصل الخدمة | قارن ترويسات المصافحة المنقحة؛ فقد يكون الجسم صفحة بوابة لا خطأ منصة منظمًا | اضبط `Origin` على مخطط `API_URL` ومضيفه. على عميل Socket.IO المباشر ضبطها؛ ويشتقها SDK `0.18.0` من `api_url`. |
| يتصل عميل Socket.IO المبني يدويًا بشكل مختلف عن SDK | يختلف المسار أو ترويسة مفتاح API أو النقل | افحص المصافحة المنقحة: المسار والنقل ووجود `x-api-key` | أرسل `x-api-key`، واختر `transports: ["websocket"]`، وسجل المعالجات قبل الاتصال |
يستخدم الإصدار `0.18.0` المسار `/socket.io` افتراضيًا؛ ولا تضبط `API_PATH`
إلا لتجاوز موثق. وتتطلب نقطة النهاية القديمة `sautech.humain.com` المسار
`/realtime/socket.io`. أبقِ الاعتمادات في عملية على الخادم؛ نقل المفتاح إلى
حزمة متصفح أو جوال ليس إصلاحًا للاتصال.
## أعراض الصوت والتأطير
افحص المصدر المشفر، ثم أنشئ دخل Realtime الخام الدقيق عند الحاجة:
```sh
ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,sample_rate,channels,sample_fmt \
-of default=noprint_wrappers=1 input.wav
ffmpeg -i input.wav -ar 16000 -ac 1 -c:a pcm_s16le \
-f s16le realtime.pcm
```
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يعيد Batch `422` مع `VALIDATION_FILE_CORRUPT` | الملف المرفوع تالف أو غير مدعوم | شغّل `ffprobe` واحتفظ بالحالة و`code` وبيانات الملف الوصفية الآمنة | فك الترميز أو حوّله إلى ملف صوت مشفر صالح، ثم أعد المحاولة مرة كرفع جديد |
| يقبل النسخ السريع الرفع من دون نتيجة نهائية مفيدة | تستخدم الحمولة المكتملة حاوية غير مدعومة أو MP4 مشوهًا | تأكد من أنها AAC أو FLAC أو MP3 أو MP4 أو WAV وافحص تخطيط MP4 | أرسل ملفًا مكتملًا مدعومًا واحدًا، وضع ذرة `moov` في مقدمة MP4 |
| نص Realtime فارغ أو مشوه أو سريع جدًا أو بطيء جدًا | أُرسلت حاوية WAV/MP3 أو عينات big-endian أو تردد أو عدد قنوات خاطئ كـPCM | افحص المصدر بـ`ffprobe` وأمر التحويل؛ يجب أن يكون طول حمولة PCM زوجيًا | أرسل بايتات PCM16 little-endian بلا ترويسة، بتردد 16 kHz وأحادية القناة |
| لا يستقبل عميل Realtime مباشر شيئًا | ترويسة التطبيق ذات 18 بايت أو UUID أو الرايات أو بايت اللغة خاطئ | افحص البايتات `0..17`، وتأكد من إعادة استخدام UUID واحد وأن الصوت يبدأ في البايت `18` | في `audio_stream` أرسل الرايات `1` مرة و`0` وسطًا و`2` مرة في النهاية، واستخدم بايت اللغة الموثق |
| لا يصل التمييز المباشر إلى النهائية | تأطير `diarization_stream` أو راية النهاية مفقود | تحقق من الترويسة نفسها ذات 18 بايت ومن UUID واحد وبت البداية وبت النهاية | أرسل PCM16 LE بتردد 16 kHz وأحاديًا وإطار نهاية واحدًا بالضبط، وأبقِ بتات الرايات الأخرى صفرًا |
| تصل التحديثات بإيقاع غير منتظم | تختلف أحجام الحمولات كثيرًا عن المساعدات المختبرة | احسب بايتات الصوت بعد الترويسة ذات 18 بايت | ابدأ بـ3,200 بايت صوت لكل إطار Realtime ASR؛ ويوصي SDK بـ15,360 بايت لكل تغذية تمييز مباشر |
أحجام الإطارات إيقاعات مختبرة، وليست ضمانات إنتاجية أو زمن وصول. ينشئ SDK
الترويسات؛ افحصها فقط عند بناء تطبيق سلكي مباشر.
## أعراض اللغة والنموذج
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يُتعرف على كلام عربي-إنجليزي كلغة واحدة | لا تصف اللغة والنموذج تبديل اللغتين | سجل قيم التعداد الدقيقة لا تسمياتها فقط | استخدم `Language.ArEn` مع `BatchTranscriptionModel.BayanArEn` أو `FastTranscriptionModel.BayanArEn` |
| يكون النسخ السريع فارغًا مع نموذج اتصالات 8 kHz | فُرض نموذج خاص بـBatch على مسار Fast | لا يوجد `NidaArTelephony` في `FastTranscriptionModel` في `0.18.0` | استخدم `BatchTranscriptionModel.NidaArTelephony` مع Batch، ولا تمرر سلسلته السلكية إلى Fast |
| تتصرف لغة غير متوقعة كالعربية | وصلت سلسلة غير معروفة إلى محول البروتوكول | سجل القيمة الدقيقة الممررة إلى SDK؛ تُحوّل السلاسل المجهولة إلى معرّف البروتوكول `0` في `0.18.0` | مرر `Language.Ar` أو `Language.En` أو `Language.ArEn` بدل تسمية حرة |
| يتضمن إعداد Realtime نموذج ASR خاصًا بـBatch أو Fast | عومل Realtime كمسار ملفات | افحص نوع الاستدعاء؛ يختار `RealtimeClient.startStream()` / `start_stream()` اللغة لا نموذج ASR | احذف خيار النموذج ومرر قيمة `Language` الصحيحة |
| يفشل TTS عبر HTTP المباشر عند عدم تحديد نموذج | يترك المسار المباشر وحده اختيار النموذج للنشر، وقد يختلف الافتراضي المضبوط أو لا يكون متاحًا. أما SDK فيرسل دائمًا `nebula` عند حذف `model`، لذا لا يقع هذا عبر `TTSClient` | سجل حدث `error` المنظم وحمولة الطلب من دون النص إذا كان حساسًا | أرسل مفتاح النموذج الصريح `nebula` على المسار المباشر بدل الاعتماد على إعداد النشر |
استخدم الاسم المستعار غير المرقّم `BayanArEn` لافتراضي تبديل اللغتين في
الإصدار المنشور. اختر `BayanArEnV1` أو `BayanArEnV2` فقط عندما تحتاج عمدًا
إلى ذلك النموذج المحدد. راجع [النماذج واللغات](/ar/models).
## أعراض غياب الإشارات النهائية والمهل
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| لا يعود عمل Batch من المساعد | ظل غير نهائي أو أصبح `cleared` أو تجاوز مهلة المساعد | سجل كل حالة: `queued` أو `processing` أو `done` أو `failed` أو `cleared` | استخدم مهلة استعلام محدودة، وتوقف عند `done` أو `failed` أو `cleared`، واستدعِ `getResult()` / `get_result()` مباشرة عند الحاجة إلى معالجة `cleared` فورًا |
| يصل إقرار رفع Fast لكن لا يكتمل الطلب | اعتُبر `audio_file_upload_success` اكتمالًا للنسخ | طابق `id` ثم تحقق من `transcription_result.is_final === true` | انتظر ضمن مهلة تطبيق فقط؛ القيمة الافتراضية لـ`timeout_seconds` في Python هي 60، بينما لا يملك JavaScript `0.18.0` خيار مهلة لطلب Fast |
| يعود `RealtimeStream.close()` / `close()` من دون رصد `is_final` على مستوى البروتوكول | انتهت مهلة انتظار النهاية المحدودة | تتبع `is_final` الطرفية على السلك؛ انتظار الإغلاق الافتراضي ثانية واحدة | تمثل `is_speech_final` حد كلام فقط ولا تحقق شرط مساعد SDK. احتفظ بالنص المؤكد ووسم النتيجة غير مكتملة. |
| يعيد `close()` للتمييز خطًا زمنيًا بلا تحديث نهائي | انتهت مهلة إغلاقه ذات خمس ثوانٍ | تتبع `isFinal` / `is_final` في آخر تحديث؛ الخط الزمني المعاد أفضل لقطة معروفة | وسمه غير مكتمل ما لم تُرَ النهائية، واحتفظ باللقطة الموفقة وافصل |
| تنتهي مهلة TTS بين المقاطع أو لا يرسل المقطع النهائي | انتهى انتظار خمول كل مقطع أو لم يصل البت 0 في البايت `16` | سجل وقت كل إطار `tts_audio` وقيمة `is_last` | افصل بين حد خمول المقطع وحد التوليف كله؛ افتراضي JavaScript لكل مقطع 30 ثانية، بينما لا يضع Python افتراضيًا |
تختلف مهلة SDK عن المهلة النهائية للتطبيق. قد تحد مهلة SDK استعلامًا أو
انتظار إغلاق أو المقطع التالي. يجب أن تحد مهلة التطبيق العملية كلها، بما فيها
الاتصال والعمل والنهائية وإعادات المحاولة. لا تثبت المهلة مطلقًا إخفاق رفع أو
وصول تدفق إلى النهائية.
## أعراض نتائج التسميات والتمييز
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| تكرر التسميات المباشرة النص المؤقت | أُلحقت كل `transcription_result` | سجل `id` وترتيب الوصول و`seq` و`is_final` و`is_speech_final` | أبقِ سطرًا مؤقتًا واحدًا قابلًا للاستبدال لكل `id`، وثبّت كلمات الأحداث النهائية أو نهاية الكلام فقط |
| يحتفظ `RealtimeSubtitles` بحدث واحد فقط من عدة أحداث نهائية | يزيل المساعد التكرار حسب `id:seq`، لكن العقد السلكي الحالي لا يضمن قيم `seq` متميزة | قارن عدد الأحداث النهائية وقيم `seq` مع `RealtimeSubtitles.words` | اجمع كلمات الأحداث النهائية بترتيب الوصول المرصود واعرضها باستخدام `Subtitles` بعد الإنهاء |
| تتكرر أدوار المتحدثين أو تختفي أو تقفز | جُمعت `final_segments` و`active_segments` الخام بلا توفيق | قارن المصفوفات الخام المتتابعة مع `update.segments` | اجمع المقاطع النهائية غير المشاهدة، واستبدل الذيل النشط، ورتب حسب البدء، أو استهلك `update.segments` الموفقة في SDK |
| لا تحمل كلمات Batch متحدثًا رغم وجود التمييز | الخط الزمني للكلمات منفصل عن خط التمييز في شكل الاستجابة | افحص `final_word_segments` / إزاحات الكلمات و`diarization_segments` | وفّق بالتداخل الزمني وحدد قاعدة تطبيق للفجوات أو التداخل الملتبس، ولا تخترع متحدثًا بصمت |
يتجاهل `RealtimeSubtitles` عمدًا الاستجابات المؤقتة ويلغي تكرار الاستجابات
النهائية حسب `id` و`seq`؛ وهذا السلوك نفسه قد يدمج أحداثًا نهائية متميزة بموجب
العقد السلكي الحالي. تظل `active_segments` في التمييز المباشر قابلة للمراجعة
حتى تنتقل إلى الحالة النهائية.
## أعراض أصوات TTS والتشغيل
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| تعيد `listVoices()` / `list_voices()` القيمة `[]` | لا تتوفر نسخة فعلية أو أكثر تحتاجها الهويات المهيأة | سجل طول المصفوفة وأي `error` منظم، ولا تفهرس العنصر `0` | تعامل مع الحالة الفارغة ولا تخمّن `voice_id`، وأعد المحاولة ضمن سياسة محدودة فقط |
| ينتظر اكتشاف الأصوات بلا نهاية في Python أو تنتهي مهلته في JavaScript | تختلف قيم المهلة الافتراضية | يفترض JavaScript خمس ثوانٍ، ولا يضع Python افتراضيًا | مرر `listVoices({ timeoutSeconds: 5 })` أو `list_voices(timeout_seconds=5)` صراحة |
| لا يشغل مشغل الوسائط بايتات التوليف | يعيد Socket.IO TTS PCM خامًا لا ملف WAV | تأكد من وصول الاستجابة إلى `is_last` وافحص عدد البايتات | عامل البايتات كـPCM16 LE بتردد 24 kHz وأحادي، وأضف ترويسة WAV صحيحة باستخدام [وصفة TTS إلى WAV المختبرة](/ar/recipes/text-to-speech-to-file) |
| خرج WAV في JavaScript مبتور أو يحتوي بايتات غير مرتبطة | حُوّل عرض `Uint8Array` بلا إزاحته وطوله | قارن `byteLength` مع `Buffer.length` الناتج | أنشئ `Buffer` باستخدام `byteOffset` و`byteLength` للعرض |
| توقفت الشيفرة التي تطابق `label` رأيته سابقًا عن إيجاد الصوت | تعرض القائمة تسميات هويات مثل `mul_` لا تسميات النسخ الفعلية | افحص بيانات `profile` المعادة | طابق معرّف الهوية `id` وخزّنه، ولا تطابق `label`؛ تُرفض معرّفات النسخ الفعلية |
| اختارت هوية متعددة اللغات النسخة الفعلية غير المتوقعة | يتطلب التوجيه العربي حرفًا من محارف الكتابة العربية في `text` | افحص النص بحثًا عن حرف من محارف الكتابة العربية | يختار أي حرف عربي النسخة العربية؛ وإلا تُختار الإنجليزية |
عند التحليل المباشر لـSocket.IO، تبدأ كل حمولة `tts_audio` بمعرّف UUID من
16 بايت وبايت ترويسة واحد. ألحق البايتات `17..end` فقط؛ البت 0 في البايت
`16` هو الإشارة النهائية.
## أعراض حدود المعدل وإعادة المحاولة
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يرفع Batch `BatchTranscribeRateLimitError` أو يعيد `429` | سعة الصوت غير متاحة مؤقتًا للطلب | افحص `retryAfter` / `retry_after` و`capacity` و`retryable` و`code` عند وجودها | احترم التأخير المرسل، وأضف تراجعًا أسيًا مع jitter، وضع حدًا للمحاولات والمدة الكلية |
| يبدو أن `maxRetries` / `max_retries` لا يفعل شيئًا | هو مهمل ومتجاهل في `0.18.0` | يصدر SDK تحذير إهمال عند استخدام قيمة غير صفرية | نفّذ سياسة إعادة المحاولة المحدودة في كود التطبيق |
| يفشل الاتصال بعد إرسال رفع | النتيجة ملتبسة | سجل ما إذا وصل معرّف عمل أو إقرار رفع | لا ترفع مجددًا بلا تمييز؛ لا ينشر API عقد idempotency-key، فطبّق سياسة تطبيق لمنع التكرار أو صعّد بالأدلة |
| يقول `error` في Socket.IO إن `retryable: true` | صنّف الخادم الحدث قابلًا لإعادة المحاولة، لا مضمون النجاح | التقط `id` و`code` و`message` و`retryable` و`timestamp` من `onError` / `on_error` | استخدم الحقل كمدخل واحد في السياسة المحدودة نفسها، ولا تكرر بلا نهاية |
`capacity` حقل استجابة تشغيلي، لا حصة حساب منشورة أو ضمان توفر. لا تتكرر قراءة
حالة Batch بأمان إلا عندما يحفظ `save_result=true` الناتج النهائي قبل جلبه؛
وقد تمسحه القراءة الافتراضية. يظل تكرار رفع لا تُعرف نتيجته غير آمن. راجع
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
## أعراض التنظيف وتسرب الاتصالات
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| تظل العملية حية بعد اكتمال العمل | ظل عميل Socket.IO أو جلسة HTTP في Python مفتوحًا | سجل إنشاء العميل والإشارة النهائية والتنظيف مرة لكل عملية؛ قد يبلغ Python عن جلسة غير مغلقة | ضع التنظيف في `finally`، واستدعِ `FastTranscriptionClient.close()` أو `TTSClient.close()` أو `RealtimeClient.disconnect()` أو `RealtimeDiarizationClient.disconnect()` حسب الحالة |
| يزداد عدد الاتصالات بعد الأخطاء أو المهل | يُنشأ عميل جديد قبل إغلاق العميل المخفق | قارن أعداد استدعاءات الاتصال والانفصال | أعد استخدام عميل سليم واحد حيث يلزم، وأغلق العميل المخفق قبل إعادة المحاولة |
| ينتهي تدفق بلا تنظيف | خرجت حلقة النتائج قبل `stream.close()` | سجل ما إذا نُفذ الدخل النهائي ومسار الإغلاق | أغلق التدفق داخل `finally`، ثم افصل العميل إذا وقع الإخفاق خارج تنظيف التدفق المعتاد |
| يحذر Python Batch من جلسة `aiohttp` غير مغلقة | تم تخطي `BatchTranscribeClient.close()` / `close_sync()` | أعد إنتاج طلب واحد وراقب إغلاق العملية | استخدم مدير السياق المتزامن أو غير المتزامن، أو استدعِ طريقة الإغلاق المطابقة داخل `finally` |
تُعد `BatchTranscribeClient.close()` في JavaScript عملية توافق لا تفعل شيئًا
في `0.18.0`؛ إذ تستخدم طلباته `fetch`. تملك عملاء JavaScript الأخرى اتصالات
Socket.IO وتتطلب مسارات التنظيف الموثقة.
## صعّد بأدلة قابلة لإعادة الإنتاج
أعد محاولة دخل واحد معروف فقط عندما تكون النتيجة غير ملتبسة وتسمح السياسة.
إذا استمرت المشكلة، فأرسل إلى جهة الاتصال في HUMAIN مثالًا مصغرًا وهذا السجل
المنقح:
```yaml
sdk: "@humain-voice/sdk@0.18.0 | humain-voice==0.18.0"
operation: "batch | fast | realtime | diarization | tts | voice-list"
api_url_host: "host only"
api_path: "Socket.IO path or not-applicable"
started_at_utc: "ISO-8601 timestamp"
request_or_job_id: "UUID if available"
input: "codec, sample_rate, channels, duration, byte_count"
observed: "http_status, event, final_signal"
error: "code, message, retryable, timestamp"
retries: "count and delays"
cleanup: "final frame, stream close, client disconnect"
```
أرفق أصغر مثال كود يعيد إنتاج المشكلة واذكر الإشارة النهائية المتوقعة. لا
ترسل مفتاح API، أو رابط Socket.IO كاملًا يحتوي سلسلة الاستعلام، أو صوتًا أو
نصًا حساسًا بلا تصريح. عند التباس نتيجة رفع، أرسل نافذته الزمنية بتوقيت UTC
وبصمة دخل آمنة وأي معرّف عمل أو طلب بدل إعادة إرساله.
لا تنشر هذه الوثائق رابط حالة انقطاع أو مدة احتفاظ أو حصة أو هدف توفر أو
ضمانًا لزمن استجابة الدعم. صعّد إخفاقات الاعتماد ونطاق الوصول إلى مصدر
المفتاح، وصعّد إخفاقات البروتوكول أو النهائية القابلة للتكرار بالأدلة أعلاه.
---
# النسخ الدفعي
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/batch-rest
استخدم Batch REST عندما يكون التسجيل الكبير أو الطويل موجودًا كاملاً ويكون
الاكتمال غير المتزامن مقبولاً. فهو يناسب الاجتماعات والبودكاست والأرشيفات
والملفات المكتملة المشابهة: ارفع مرة، واستلم `jobId`، واستعلم عن المهمة حتى
حالة طرفية.
يقبل النسخ Fast أيضًا صوتًا مكتملاً، لكن اختره لوحدة محادثة واحدة حساسة لزمن
الاستجابة. وإذا كان الصوت لا يزال يصل، فاستخدم
[سير عمل Realtime](/ar/api-guides/realtime) بدلاً منه.
## 1. جهّز خادمًا موثوقًا
تحتاج طلبات Batch المباشرة إلى القيم والقرارات التالية:
| المتطلب | ما يجب تجهيزه |
|---------|---------------|
| `API_URL` | استخدم عنوان REST الأساسي الدقيق الصادر لبيئتك؛ لا تستنتج مضيفًا |
| `API_KEY` | أرسله في `x-api-key` من خلفية موثوقة، وليس من شيفرة عميل عامة |
| صوت مكتمل | ارفع ملفًا واحدًا في الحقل `file` من جسم `multipart/form-data` |
| المهل | ضع مهلة لكل طلب ومهلة محدودة للعمل كله |
اتبع [تدفق الوصول الموثق](/ar/authentication) إذا لم تكن لديك
القيمتان `API_URL` و`API_KEY`. الإعداد `API_PATH` خاص بـ Socket.IO ولا تستخدمه
مسارات REST هذه.
## 2. أرسل عملاً
اختر مسار اللغة ومحددات المعالجة قبل الرفع. يطلب هذا المثال تبديل الشيفرة بين
العربية والإنجليزية، وتمييز المتحدثين، والتسوية العكسية للنص:
```bash
curl --fail-with-body --connect-timeout 10 --max-time 120 \
-X POST "$API_URL/v1/transcribe/codeswitch?asr=bayan_cs_ar_en&diarization=1&itn=1&redact=0" \
-H "x-api-key: $API_KEY" \
-F "file=@meeting.wav"
```
يعيد إنشاء المهمة الناجح HTTP `200`. يتضمن التعريف المتحقق منه هذه الاستجابة:
```json
{
"jobId": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"status": "queued"
}
```
تحقق من حالة HTTP قبل تحليل شكل النجاح، ثم احتفظ بـ `jobId` مع عنصر العمل في
تطبيقك؛ فهو المعرّف المستخدم في قراءات النتيجة التالية.
### محددات المعالجة
| المحدد | الموقع | القيم المقبولة | الأثر |
|--------|--------|----------------|-------|
| `lang` | المسار | `en`، `ar`، `codeswitch`، `auto` | يختار سير عمل لغة النسخ |
| `asr` | الاستعلام | قيمة النموذج المنشورة على البروتوكول | يتجاوز النموذج المختار للغة |
| `diarization` | الاستعلام | `0`، `1`، `d1`، `d2` | يختار تمييز المتحدثين |
| `itn` | الاستعلام | `0`، `1` | يفعّل التسوية العكسية للنص |
| `redact` | الاستعلام | `0`، `1` | يفعّل التنقيح |
استخدم [خريطة النماذج](/ar/models) لقيم النماذج المنشورة على البروتوكول. لا
تخترع لاحقة نموذج لا تعرضها الخريطة.
## 3. استعلم من مسار نتيجة V2 بمهلة
اقرأ نتيجة V2 المباشرة باستخدام UUID العائد للعمل:
```bash
export JOB_ID=""
curl --fail-with-body --connect-timeout 10 --max-time 15 \
"$API_URL/v1/transcribe/$JOB_ID?save_result=true" \
-H "x-api-key: $API_KEY"
```
يعيد `GET /v1/transcribe/{job_id}` الشكل
`{ "message": "success", "data": … }`. اتخذ القرار من `data.status` فقط:
| الحالة | إجراء التطبيق |
|--------|---------------|
| `queued` | انتظر ثم اقرأ مجددًا ما دامت المهلة الكلية باقية |
| `processing` | استمر في الانتظار ضمن المهلة نفسها |
| `done` | أوقف الاستعلام واستخدم حقول النتيجة المكتملة |
| `failed` | أوقف الاستعلام وأظهر فشل العمل |
| `cleared` | أوقف الاستعلام؛ النتيجة غير متاحة |
استخدم تسلسل الاستعلام المحدود التالي:
1. ضع مهلة كلية واحدة قبل أول قراءة للنتيجة.
2. أعط كل GET مهلة طلب مستقلة أقصر.
3. اقبل `queued` و`processing` فقط سببًا للانتظار والاستعلام مجددًا.
4. توقف فورًا عند `done` أو `failed` أو `cleared`.
5. توقف محليًا عند انتهاء المهلة الكلية؛ لا تستنتج حالة طرفية على الخادم من
مهلة العميل.
اضبط `save_result=true` قبل أول استعلام عندما يجب أن يكون تسليم الاستجابة
النهائية قابلاً للتكرار. مع القيمة الافتراضية `false`، قد تمسح قراءة `done` أو
`failed` حقول النتيجة المخزنة بعد بناء الاستجابة. إذا ضاعت تلك الاستجابة، فقد
تعيد القراءة التالية `cleared` بدل النتيجة.
فاصل الاستعلام والمهلة خياران للتطبيق، وليسا ضمانين للخدمة. توفر
[وصفة التسجيل](/ar/recipes/transcribe-a-recording) حلقات JavaScript وPython
محدودة.
## 4. افصل V1 عن V2
| المسار | الاستخدام المقصود | شكل الاستجابة | محددات النتيجة الاختيارية |
|--------|--------------------|----------------|----------------------------|
| `GET /v1/transcribe/{job_id}` | قراءة نتيجة V2 المباشرة | غلاف مع `data.final_result` و`data.final_word_segments` و`data.diarization_segments` | `save_result`، وقيمته الافتراضية `false` |
| `GET /v1/transcribe/{job_id}/{lang}` | V1 القديم وSDK `0.18.0` | `metadata` و`results.transcript` و`results.offsets` و`diarization_segments` | `save_result`، وقيمته الافتراضية `false`؛ ولـHTTP المباشرة فقط: `diarization_force_align`، وقيمته الافتراضية `true` |
يستخدم الشكلان حالات المهمة الخمس نفسها، لكن أسماء الحقول وتداخلها مختلفان. لا
تخلط مقاطع كلمات V2 ذات snake-case مع إزاحات V1 في نوع واحد. قد تجعل القيمة
الافتراضية `save_result=false` استجابة `done` أو `failed` النهائية قراءة أحادية
الاستهلاك في كلا المسارين. اضبطها إلى `true` قبل الاستعلام عندما يجب استرجاع
النتيجة بعد فقد استجابة. لا يحدد العقد مدة احتفاظ حتى مع `save_result=true`؛
عامل `cleared` كحالة طرفية من دون افتراض إمكان الاستعادة.
يبقى مقطع `lang` في V1 للتوافق، لكن معالج النتيجة الحالي لا يستخدمه ولا يتحقق
منه. ترسل حزم SDK في الإصدار `0.18.0` لغة الإرسال؛ وينبغي لعملاء HTTP
المباشرين الجدد استخدام V2.
## 5. وفّق التمييز
لا تحتوي `final_word_segments` في V2 على `speaker`. عند تفعيل التمييز، وفّق
كل كلمة مع `diarization_segments` بقاعدة توثقها في تطبيقك، مثل إسناد المقطع
الذي يحتوي منتصف الكلمة. احتفظ بمتحدث مجهول عند عدم وجود تداخل، ما لم يتبن
تطبيقك صراحة إسناد أقرب مقطع.
يمكن لمسار V1 وضع `speaker` على إزاحات الكلمات. يغير خيار
`diarization_force_align` المخصص لـHTTP المباشرة تسميات تلك الإزاحات، لا
`diarization_segments` الخام؛ ولا تعرضه حزم SDK في الإصدار `0.18.0`. مع القيمة
الافتراضية `true`، تُسند الكلمة التي يقع `startTime` لها خارج كل المقاطع
الحقيقية إلى متحدث أقرب حد مقطع استنادًا إلى منتصف الكلمة، ويُختار المقطع
الأسبق عند التعادل. مع `false` تستخدم `UNKNOWN_SPEAKER`. وإذا لم توجد مقاطع
حقيقية فتبقى `speaker` بقيمة `null`.
تصف تسميات المتحدثين أدوارًا نسبية في نتيجة واحدة، ولا تثبت هوية حقيقية.
## 6. تعامل مع السعة والمحاولات الملتبسة
قد يعيد إرسال Batch حالة HTTP `429` مع حقول خطأ منظمة والسعة المتبقية بثواني
الصوت في `data.capacity`:
```json
{
"error": "error.rate_limit",
"code": "RATE_LIMIT_EXCEEDED",
"detail": "error.rate_limit",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z",
"data": { "capacity": 120.5 }
}
```
عند استجابة `429` صريحة، ضع المنتجين في طابور أو أبطئهم، وأعد المحاولة بعدد
محاولات وتراجع ومهلة كلية محدودة. استخدم `capacity` لقرارات القبول؛ فلا يعرّفها
العقد كمدة انتظار.
يختلف انقطاع الاتصال أو انتهاء المهلة بعد الرفع: قد يكون الطلب الأول أنشأ
عملاً بالفعل. لا يوثق عقد Batch ترويسة لمفتاح idempotency، لذلك لا تعد الإرسال
بلا تمييز. سجل المحاولة الملتبسة، ولا تعدها إلا وفق سياسة تطبيق تقبل صراحة خطر
تكرار العمل. لا تستخدم محاولات محدودة لطلبات GET إلا عندما ضُبط
`save_result=true` قبل جلب الحالة النهائية؛ فقد تتحول القراءة الهدامة الافتراضية
إلى `cleared` بعد فقد الاستجابة. راجع
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
## 7. انتقل إلى المرجع وتحققات الإنتاج
نفذ تسجيلاً ممثلاً واحدًا أولاً، ثم أبق مرجع Batch API المولد بجانب شيفرتك
للمخططات الدقيقة. وقبل الإطلاق، اختبر فشل المصادقة، والصوت غير الصالح، و`429`،
ومهل الاستعلام، والنتائج الطرفية الثلاث كلها.
---
# الأخطاء وحدود المعدل
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/errors-and-rate-limits
عند أي فشل، احتفظ أولاً بالإشارة، وأوقف العمل المتأثر، وحدد هل النتيجة معلومة.
لا تعد المحاولة إلا عندما تكون العملية آمنة للتكرار، وتسمح الحالة المنظمة بذلك،
وتبقى مهلة للتطبيق.
## 1. صنّف موضع ظهور الفشل
| السطح | ما تلاحظه | الإجراء الأول |
|-------|------------|---------------|
| النقل | فشل اتصال أو قراءة أو خمول أو انقطاع من دون استجابة منصة | عامل النتيجة كمجهولة حتى يثبت عقد العملية أمان التكرار؛ أوقف وسيلة النقل المتأثرة وأغلقها |
| HTTP | حالة غير 2xx وجسم `ErrorResponse` منظم غالبًا | احتفظ بالحالة والجسم، ثم اتخذ القرار من `code` و`retryable` |
| Socket.IO | حدث `error` منظم مع `code` و`message` و`retryable` و`timestamp` و`id` اختياري | أوقف تغذية الطلب أو البث الموجه قبل اتخاذ قرار التعافي |
| SDK | استثناء Batch ذو نوع، أو استدعاء Socket.IO منظم، أو رفض عام بعد الإسقاط | استخدم أغنى إشارة ذات نوع أو استدعاء متاح؛ لا تتخذ القرار من نص الاستثناء |
غياب الاستجابة ليس مساويًا لـ`retryable: true`. كما أن
`retryable: true` المنظمة لا تكفي وحدها؛ فقد يظل تكرار الرفع أو البث المنقطع
غير آمن أو ملتبسًا.
## 2. احتفظ بحقول HTTP وSDK
تستخدم عمليات Batch REST وHTTP المباشر المحمية شكل HTTP المسمى
`ErrorResponse`:
| الحقل | المعنى |
|-------|--------|
| `error` | معرّف قديم؛ احتفظ به للتشخيص والتوافق |
| `code` | فئة قابلة للقراءة آليًا لاتخاذ قرار التطبيق |
| `detail` | تفصيل بشري اختياري؛ لا تتخذ القرار من صياغته |
| `message` | رسالة قديمة اختيارية في بعض استجابات المصادقة |
| `job_id` | UUID اختياري لعمل Batch أو تدفق Realtime HTTP مرتبط بالفشل |
| `request_id` | معرّف ارتباط اختياري لطلب Batch |
| `retryable` | هل يصنف الخادم فشل هذا الطلب قابلاً لإعادة المحاولة |
| `timestamp` | توقيت الخادم |
| `data` | دليل منظم اختياري للحد أو التحقق؛ احتفظ بحقوله ووحداته |
يعني مثال Batch المتحقق منه هذا «صحح الجسم متعدد الأجزاء ولا تعده من دون
تغيير»:
```json
{
"error": "error.api.error.multipart.file.missing",
"code": "VALIDATION_REQUIRED_FIELD",
"detail": "error.api.error.multipart.file.missing",
"retryable": false,
"timestamp": "2026-01-15T10:30:00Z"
}
```
تحقق دائمًا من حالة HTTP قبل اختيار محلل النجاح. احتفظ بالجسم الخام عندما
يفشل التحليل المنظم.
يعرض SDK `0.18.0` إسقاطات مختلفة:
| سطح SDK | المعلومات المنظمة |
|---------|--------------------|
| Batch في JavaScript | يعرض `BatchTranscribeError` القيم `statusCode` و`payload` و`code` و`retryable` و`jobId` و`detail` و`timestamp` و`capacity` و`rawBody`؛ وتضيف أخطاء حد المعدل `retryAfter` |
| Batch في Python | يعرض `BatchTranscribeError` القيم `status_code` و`payload` و`code` و`retryable` و`job_id` و`detail` و`timestamp` و`capacity` و`raw_body`؛ وتضيف أخطاء حد المعدل `retry_after` |
| استدعاءات Socket.IO | يحتفظ `ErrorResponse` في SDK بالقيم الاختيارية `id` و`message` و`code` و`retryable` و`timestamp` و`retry_after_seconds` و`data` و`reason` و`retry_scope` |
| رفض TTS بسبب خطأ الخادم | ترفض JavaScript بـ`Error` عام، وترفع Python `RuntimeError` عامًا؛ يحتفظ الرفض بالرسالة فقط، لذلك سجل الحقول المنظمة في `onError` / `on_error` |
| رموز حدود العمل | يحتفظ SDK `0.18.0` بالحقل `data`، ويصنف رموز الحدود الحالية، ويوجه الرفض الحامل للمعرّف إلى سياق الطلب النشط. يظل الاستدعاء العام يعمل أولًا، ثم يُرفض استدعاء التوليف بخطئه العام الذي يحتفظ بالرسالة فقط. |
| رموز سياسة محتوى TTS | يصدر SDK `0.18.0` الثابتين `TTS_INPUT_NOT_ALLOWED` و`TTS_MODERATION_UNAVAILABLE`، ويصنفهما على أنهما مملوكان لـTTS، ويوجه الخطأ الحامل للمعرّف إلى سياق التوليف النشط |
استمر في التحقق من دخل TTS قبل الإرسال، ومرّر دائمًا مهلة صريحة
(`timeoutSeconds` في JavaScript و`timeout_seconds` في Python). اقرأ `code`
و`data` من استدعاء الخطأ العام قبل رفض الطلب؛ فالاستثناء العام يحتفظ بالرسالة
فقط.
## 3. طبّق جدول القرار
| الحالة المرصودة | تفسير النتيجة | الإجراء |
|-----------------|---------------|---------|
| `400` أو رمز تحقق | الطلب غير صالح | صحح UUID أو المعاملات أو التأطير أو الملف أو الصوت؛ لا تعده من دون تغيير |
| `401` أو رمز مصادقة | المفتاح مفقود أو غير صالح | صحح بيانات الاعتماد قبل طلب آخر |
| `403` مع `AUTH_FORBIDDEN` | قبلت المنصة المفتاح لكنه لا يملك القدرة | حدّث الوصول عبر مسار إدارة المفاتيح في مؤسستك؛ لا تعد الطلب من دون تغيير |
| استجابة `403` أخرى | رفضت بوابة أو طبقة وسيطة الطلب | احتفظ بالجسم الخام أو معرّف الدعم، ثم تحقق من العنوان والمسار وبيانات الاعتماد وأي ترويسات خاصة بالنشر |
| `404` / `TRANSCRIPTION_JOB_NOT_FOUND` | المهمة المطلوبة غير متاحة تحت UUID ذلك | أوقف الاستعلام عن UUID ذلك، وتحقق من المعرّف المخزن |
| `405` / `METHOD_NOT_ALLOWED` | المسار أو الطريقة خطأ | صحح التوجيه قبل طلب آخر |
| Realtime TTS `422` / `CHARACTER_COUNT_EXCEEDED` | النص، أو نص مرجع الصوت، أطول من الحد المسموح. يحدد `data.bound` أيهما: `tts_input_characters` أو `tts_voice_reference_text_characters` | اختصر النص بالاستناد إلى `data.limit`، ولا تعد الطلب نفسه بلا تغيير |
| Realtime TTS `422` / `VOICE_REFERENCE_COUNT_EXCEEDED` | أكثر من عنصر واحد في `voice_references`؛ يُقبل عنصر واحد فقط | أرسل مرجعًا واحدًا، ولا تعد الطلب نفسه بلا تغيير |
| Realtime TTS `422` / `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة `tts_voice_reference_duration` | مقطع المرجع أطول من حد المرجع المضبوط في النشر، وقد يضبطه النشر أقل من حد النموذج نفسه | اقتطع المقطع إلى `data.limit` ثانية — و`data.limit` هي المرجع لا أي قيمة افتراضية منشورة، ولا تعد الطلب نفسه بلا تغيير |
| Realtime TTS `413` / `PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` | الحجم المفكوك لمقطع المرجع يتجاوز الحد | أرسل مقطعًا أقصر أو بمعدل عينات أقل، ولا تعد الطلب نفسه بلا تغيير |
| TTS `400` / `TTS_INPUT_NOT_ALLOWED` | رفضت سياسة المحتوى النص؛ ولن يُقبل النص نفسه | غيّر النص قبل إرسال طلب آخر، ولا تعده بلا تغيير |
| TTS `503` / `TTS_MODERATION_UNAVAILABLE` | تعذر على جهة الإشراف على المحتوى اتخاذ قرار، فأوقف التوليف بصورة مغلقة | لا تعامل الحالة كرفض لسياسة المحتوى. لا تعد المحاولة إلا بعد تراجع محدود وما دامت مهلة التطبيق باقية |
| `402` / `CREDITS_EXHAUSTED` | نفد الرصيد ولا يمكن لإعادة فورية استعادته | أوقف العمل المتأثر ولا تعد الطلب من دون تغيير. يكون الحدث في منتصف تدفق Realtime طرفيًا ويتبعه فصل. |
| `503` / `BILLING_AUTHORIZATION_UNAVAILABLE` | لم تتمكن جهة الفوترة من اتخاذ قرار، فأخفقت المنصة بصورة مغلقة | أوقف العمل المتأثر ولا تعده إلا بعد تراجع محدود. يكون الحدث في منتصف Realtime طرفيًا ويتطلب تدفقًا جديدًا. |
| Realtime `409` / `ASR_STREAM_EXPIRED` | أنهى خمول الصوت أو فقد تسلسل الخلفية تدفق ASR هذا | اقرأ `reason`، وتحقق من `retry_scope: "new_stream"`، واحتفظ بالخرج المثبت، وابدأ UUID جديدًا؛ ولا تعِد الإطارات على المعرّف المنتهي. |
| `422` في Batch مع رمز تحقق مثل `VALIDATION_FILE_CORRUPT` | الملف غير مدعوم أو تالف أو فارغ أو بمدة صفرية | صحح الدخل؛ لا تعد البايتات نفسها |
| `422` / `AUDIO_DURATION_EXCEEDED` في Batch مع `data.bound` بقيمة `audio_duration` | الصوت صالح لكن مدته المفكوكة أطول من المدة المقبولة | قسّم التسجيل إلى `data.limit` ثانية أو أقل، أو أرسل ملفًا أقصر، ولا تعد الطلب نفسه بلا تغيير |
| `422` / `FILE_COUNT_EXCEEDED` في Batch | عدد الأجزاء أكبر مما يقبله الطلب الواحد. يحدد `data.bound` أيهما، ويبين `data.unit` وحدة العد: يعد `file_parts` الملفات الصوتية، ويعد `multipart_parts` كل أجزاء multipart | مع `file_parts` أرسل `data.limit` ملفًا صوتيًا على الأكثر في الطلب؛ ومع `multipart_parts` ابقِ النموذج كاملًا داخل `data.limit` جزءًا، ولا تعد الطلب نفسه بلا تغيير |
| `429` / `RATE_LIMIT_EXCEEDED` في Batch | ضغط سعة صريح | ضع عمليات الإرسال في طابور أو أبطئها، ثم استخدم سياسة إعادة محاولة محدودة |
| HTTP `5xx` مع `retryable: true` في GET لنتيجة Batch استُدعي مع `save_result=true` | فشلت قراءة نتيجة محفوظة | أعدها بتراجع محدود وjitter ما دامت المهلة باقية |
| HTTP `5xx` مع `retryable: true` في رفع | يدعو الخادم إلى الإعادة، لكن نتيجة الإنشاء قد تظل ملتبسة | لا تكرر بلا تمييز؛ طبق سياسة صريحة لخطر التكرار |
| أي استجابة مع `retryable: false` | يطلب الخادم عدم إعادة حالة الطلب هذه | توقف حتى يتغير الدخل أو بيانات الاعتماد أو المسار أو الإعداد |
| مهلة قراءة قبل أي استجابة | لا يوجد تصنيف من المنصة | لا تعد إلا قراءة يحفظ عقدها النتيجة، وضمن المهلة فقط |
| خطأ أو انقطاع Realtime | قد تكون حالة البث القديم وحد الصوت المقبول ملتبسين | توقف، واحتفظ بالنتائج المثبتة، ونظف، وتعافَ بـUUID جديد إذا سمحت السياسة |
| خطأ حل `voice_id` في TTS (SAU-2258) | `voice_id` المُرسَل من العميل الذي ليس UUID صالحًا هو `400 VALIDATION_INVALID_UUID`؛ والصالح البنية لكنه لا يحدد صوتًا متاحًا هو `400 TTS_VOICE_NOT_FOUND` (كلاهما غير قابل للإعادة). وصوت محلول بياناته المخزَّنة ناقصة أو تالفة هو `500 TTS_VOICE_RESOLUTION_FAILED` غير قابل للإعادة؛ وانقطاع عابر لقاعدة البيانات/التخزين أثناء الحل هو `503 SERVER_DEPENDENCY_FAILURE` قابل للإعادة. أما أخطاء النموذج/السعة/الاستدلال الحقيقية فتبقى `500 TTS_SYNTHESIS_FAILED` قابلة للإعادة | صحّح `voice_id` أو أرسل `voice_references`؛ وأعد محاولة `503` و`500 TTS_SYNTHESIS_FAILED` فقط مع تراجع، ولا تعد أبدًا محاولة الـ`400` غير القابلين للإعادة ولا `500 TTS_VOICE_RESOLUTION_FAILED` |
| خطأ TTS بقيمة `400` عند إرسال المحددين معًا أو مرجع مشوه | إرسال `voice_id` مع `voice_references` غير فارغة، أو مصفوفة `voice_references` فارغة صريحة، أو صوت مرجع ليس base64 قياسيًا صارمًا بصيغة RIFF/WAVE أحادي القناة PCM16، هو خطأ تحقق غير قابل للإعادة | في SDK، اختر واحدًا بالضبط من `voice_id` أو عنصر `voice_references` قياسي واحد. يسمح HTTP المباشر بحذف المحددين لاختيار يعتمد على النشر. لا ترسل المحددين معًا. |
قد تعيد بوابة النشر `429` لطلب Realtime HTTP، بينما قد تطوي خلفية Fast أو البث
الحي الحالية فشل سعة الصوت الداخلي إلى `500` قابلة للإعادة مع
`ASR_TRANSCRIPTION_FAILED`. لا تستنتج حصة Realtime أو مجموعة سعة أو نافذة
إعادة ضبط من أي من الاستجابتين أو من سعة Batch.
## 4. عامل Batch 429 كضغط سعة
يتضمن `429` في Batch الحقول المنظمة المعتادة إضافة إلى `data.capacity`:
```json
{
"error": "error.rate_limit",
"code": "RATE_LIMIT_EXCEEDED",
"detail": "error.rate_limit",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z",
"data": { "capacity": 120.5 }
}
```
`capacity` هي السعة المتبقية مقاسة بثواني الصوت. استخدمها لقرارات الطابور
والقبول. وهي ليست حصة موثقة أو نافذة إعادة ضبط أو عدد ثوانٍ للانتظار.
لا يَعِد عقد OpenAPI بترويسة `Retry-After`. لا تُملأ
`retryAfter` / `retry_after` في SDK إلا عندما توجد ترويسة صالحة فعلاً. عند
غيابها، طبق تراجعًا أسيًا محدودًا مع jitter. قيّد دائمًا المحاولات، وكل تأخير،
وزمن إعادة المحاولة الكلي، وتزامن المنتجين بمهلة كلية.
## 5. احفظ نتيجة Batch قبل إعادة قراءتها
لا يعيد SDK المنشور محاولات Batch. الخيار `maxRetries` / `max_retries` مهمل
ومتجاهل ومحتفظ به للتوافق فقط. تعيد هذه الأمثلة المختبرة
`getResult()` / `get_result()`، لا الرفع، وتمرر صراحة
`saveResult: true` / `save_result=True`. قد تمسح القيمة الافتراضية `false`
النتيجة النهائية بعد بناء الاستجابة، ولذلك قد تتبع الاستجابة المفقودة حالة
`cleared`. يتيح خيار الحفظ إعادة محدودة لكنه لا يحدد مدة احتفاظ. تستخدم الأمثلة
الخصائص ذات النوع المنشورة:
JavaScript / TypeScript
Python
```ts
import {
BatchTranscribeClient,
BatchTranscribeError,
BatchTranscribeRateLimitError,
Language,
type TranscriptionResponse,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function getResultWithRetry(
client: BatchTranscribeClient,
jobId: string,
attempts = 5,
): Promise {
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
// saveResult prevents a terminal read from clearing the stored result
// before a retry. It does not establish a retention duration.
return await client.getResult(jobId, Language.ArEn, { saveResult: true });
} catch (error: unknown) {
if (!(error instanceof BatchTranscribeError)) throw error;
const rateLimited = error instanceof BatchTranscribeRateLimitError;
const retryable = rateLimited || error.retryable === true;
console.error({
statusCode: error.statusCode,
code: error.code,
capacity: error.capacity,
});
if (!retryable || attempt === attempts) throw error;
const serverDelayMs = rateLimited && error.retryAfter !== undefined
? error.retryAfter * 1_000
: 0;
const exponentialDelayMs = 500 * 2 ** (attempt - 1);
await pause(Math.max(serverDelayMs, exponentialDelayMs) + Math.random() * 250);
}
}
throw new Error('Retry loop exhausted');
}
async function main(): Promise {
const jobId = process.argv[2];
if (!jobId) throw new Error('Pass a batch job ID as the first argument');
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
});
try {
const result = await getResultWithRetry(client, jobId);
console.info(result.status, result.results?.transcript ?? '');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import random
import sys
from humain_voice import stt
from humain_voice.stt.batchtranscription import TranscriptionResponse
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def get_result_with_retry(
client: stt.BatchTranscribeClient,
job_id: str,
attempts: int = 5,
) -> TranscriptionResponse:
for attempt in range(1, attempts + 1):
try:
# save_result prevents a terminal read from clearing the stored
# result before a retry. It does not define a retention duration.
return await client.get_result(
job_id, stt.Language.ArEn, save_result=True
)
except stt.BatchTranscribeError as error:
rate_limited = isinstance(error, stt.BatchTranscribeRateLimitError)
retryable = rate_limited or error.retryable is True
print(
{
"status_code": error.status_code,
"code": error.code,
"capacity": error.capacity,
}
)
if not retryable or attempt == attempts:
raise
server_delay = 0
if isinstance(error, stt.BatchTranscribeRateLimitError):
server_delay = error.retry_after or 0
exponential_delay = 0.5 * 2 ** (attempt - 1)
await asyncio.sleep(max(server_delay, exponential_delay) + random.random() * 0.25)
raise RuntimeError("Retry loop exhausted")
async def main() -> None:
if len(sys.argv) < 2:
raise RuntimeError("Pass a batch job ID as the first argument")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
) as client:
result = await get_result_with_retry(client, sys.argv[1])
print(result.status.value, result.results.transcript if result.results else "")
if __name__ == "__main__":
asyncio.run(main())
```
السلوك المتوقع: تستخدم القراءات القابلة للإعادة خمس محاولات على الأكثر، وتحترم
قيمة `retryAfter` / `retry_after` فعلية عند وجودها، وتضيف تأخيرًا أسيًا وjitter،
وتعيد إطلاق الفشل النهائي. لا يغني حد المحاولات عن مهلة كلية للتطبيق.
## 6. أبقِ العمليات الملتبسة خارج الإعادة الآلية
### رفع الملفات الكاملة
لا يوثق إنشاء عمل Batch وإرسال الصوت الكامل عبر Fast عقد مفتاح idempotency.
لا تثبت المهلة أو الانقطاع بعد إرسال البايتات النجاح أو الفشل؛ فقد يكون الخادم
قبل الطلب.
إذا عاد `jobId` أو UUID للطلب، فاحتفظ به وتابع مسار النتيجة المعتاد لتلك
العملية. ومن دون استجابة حاسمة، سجل المحاولة الملتبسة ولا تكرر إلا وفق سياسة
تطبيق تقبل صراحة العمل المكرر.
### بث Realtime
لا تعرّف عقود Socket.IO وHTTP العامة استئنافًا شفافًا ولا إعادة idempotent
للإطارات. عند خطأ أو انقطاع:
1. أوقف إرسال الصوت وأغلق البث أو الاستجابة القديمة.
2. احتفظ بالنتائج المثبتة وتجاهل الحالة المؤقتة غير المحسومة.
3. سجل فترة الصوت الملتبسة.
4. أعد الاتصال بتراجع محدود وUUID جديد فقط إذا سمح الخطأ ومهلة التطبيق.
5. افصل البث الجديد حتى يوفق التطبيق الخطين الزمنيين صراحة.
لا تعد الإطارات القديمة أو تستخدم UUID القديم بافتراض إزالة الخادم لتكرارها.
## 7. افصل المهل عن المهلة الكلية
| التحكم | ما يقيّده | ما يثبته الانتهاء |
|--------|-----------|-------------------|
| مهلة الاتصال أو الطلب | مرحلة شبكة أو طلب واحد | توقف العميل عن الانتظار؛ لا تثبت هل نفذ الخادم أم لا |
| مهلة القراءة أو الخمول | انتظار البايت أو المقطع أو الحدث التالي | لم يصل تقدم في تلك الفترة؛ لا تثبت مدة العملية الكلية |
| مهلة انتظار Realtime النهائي | الانتظار بعد إطار الدخل النهائي | انتهى الانتظار؛ لا تثبت وصول نتيجة نهائية |
| مهلة التطبيق الكلية | الاتصال والعمل والإعادات والتأخيرات والتنظيف معًا | يجب أن يوقف التطبيق مزيدًا من العمل |
تكون قيمة `timeoutSeconds` في TTS لـJavaScript افتراضيًا 30 ثانية من الخمول
أثناء انتظار كل مقطع صوت. لا يضع TTS في Python مهلة ما لم تمرر
`timeout_seconds`. ينتظر `close()` في Realtime ASR SDK `is_final` على مستوى البروتوكول أو
خطأ موجهًا أو مهلة الإغلاق فقط، ويمكنه العودة عند انتهاء ذلك الانتظار. لا يغني
أي من هذه الضوابط عن المهلة الكلية.
بعد أي انتهاء، نظف داخل `finally`: ألغِ قراءات HTTP وأغلق أجسام الاستجابة؛
وأوقف صوت Socket.IO واستدعِ `disconnect()` أو اخرج من سياق Python غير
المتزامن؛ وأغلق عميل Batch. لا تستنتج أن تنظيف العميل ألغى العمل على الخادم.
ولا تستنتج أنه ألغى توليف TTS جارٍ.
## 8. سجل القرارات واختبر مسارات الفشل
سجل العملية، ووسيلة النقل، وحالة HTTP أو اسم الحدث، و`code`، وقرار إعادة
المحاولة، وUUID للطلب أو العمل، ورقم المحاولة، والمهلة المتبقية، ونوع المهلة،
وسعة Batch عند وجودها. لا تسجل مفاتيح API أو الصوت الكامل أو نصًا حساسًا
افتراضيًا.
بعد ذلك، شغّل مثال القراءة الآمنة، ثم اختبر الدخل غير الصالح، والمصادقة،
و`429` الصريح، ومهلة القراءة، ومهلة رفع ملتبسة، وانقطاع Realtime، وانتهاء
انتظار النتيجة النهائية، والتنظيف في بيئة اختبار معزولة.
---
# نظرة عامة على API المباشرة
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides
استخدم هذه الأدلة عندما لا يملك وقت التشغيل SDK منشورًا، أو تحتاج تحكمًا على
مستوى البروتوكول، أو تحتاج تشخيص سلوك النقل. ينبغي لتطبيقات JavaScript وPython
أن تبدأ عادة من [أدلة SDK](/ar/sdk).
## اختر حسب دورة حياة الإدخال
| الإدخال والنتيجة | السطح المباشر | ابدأ من | أبقِ هذا مفتوحًا كعقد |
|---|---|---|---|
| اجتماع أو بودكاست أو أرشيف أو تسجيل طويل مكتمل آخر يمكن أن ينتهي بصورة غير متزامنة | **Batch REST**: ارفع مرة، واستلم `jobId`، ثم استعلم | [دليل Batch REST](/ar/api-guides/batch-rest) | [Batch OpenAPI](/ar/api-reference/batch) |
| وحدة صوت مكتملة حساسة للكمون، مثل دور محادثة واحد | **النسخ السريع**: أرسل الوحدة كاملة عبر Socket.IO `audio_file` أو HTTP متعدد الأجزاء `/realtime/http/stt` | [دليل Socket.IO](/ar/api-guides/socketio) أو [دليل Realtime HTTP](/ar/api-guides/realtime-http) | [Fast AsyncAPI](/ar/api-guides/asyncapi/fast-transcription) أو [Realtime HTTP OpenAPI](/ar/api-reference/realtime-http) |
| صوت لا يزال يصل، مع نص مباشر أو مقاطع متحدثين | **البث المباشر**: `audio_stream` / `diarization_stream` عبر Socket.IO، أو بث HTTP مؤطر | [نظرة عامة على نقل Realtime](/ar/api-guides/realtime) | [Realtime AsyncAPI](/ar/api-guides/asyncapi/realtime) و[Realtime HTTP OpenAPI](/ar/api-reference/realtime-http) |
| نص يجب أن يصبح كلامًا | **TTS**: `tts` / `tts_audio` عبر Socket.IO، أو TTS مباشر عبر HTTP مع قيد التأطير الموثق | [دليل Socket.IO](/ar/api-guides/socketio)؛ استخدم [Realtime HTTP](/ar/api-guides/realtime-http) فقط عند الحاجة إلى HTTP | [TTS AsyncAPI](/ar/api-guides/asyncapi/tts) أو [Realtime HTTP OpenAPI](/ar/api-reference/realtime-http) |
يستهلك Batch والنسخ السريع كلاهما صوتًا مكتملًا. اختر Batch للوسائط الطويلة،
وFast فقط لوحدة مكتملة محدودة يهم كمونها. لا تجعل أحداث النتائج إدخال Fast
فوريًا. اختر Realtime فقط ما دام الصوت يصل.
## المتطلبات المشتركة
- احصل على `API_KEY` عبر [مسار المصادقة](/ar/authentication)، واستخدم
`API_URL` المعروض لهذه البيئة. يستخدم SDK المسار `/socket.io` افتراضيًا؛
ولا تستنتج تجاوزًا من بيئة أخرى.
- أرسل `x-api-key` في كل طلب HTTP محمي واتصال Socket.IO. احتفظ به في خلفية
موثوقة؛ فلا تستطيع شيفرة المتصفح إبقاء مفتاح API سريًا.
- ضع مهلاً محدودة للاتصال والطلب والقراءة والاستعلام والنتيجة النهائية. تحقق
من حالة HTTP قبل تحليل النجاح، وأغلق كل بث أو مقبس.
| السطح | عقد الصوت أو الخرج المطلوب |
|---|---|
| Batch REST | رفع ملف `multipart/form-data` واحد |
| النسخ السريع | ملف مشفر مكتمل واحد في حزمة Socket.IO أو طلب HTTP متعدد الأجزاء |
| ASR المباشر والتمييز | PCM16 little-endian، بتردد 16 kHz وأحادي القناة؛ يحتوي كل جسم إدخال ترويسة التحكم الموثقة ذات 18 بايت |
| TTS عبر Socket.IO | PCM16 خام مؤطر little-endian، بتردد 24 kHz وأحادي؛ يبدأ الصوت بعد ترويسة الإطار ذات 17 بايت |
| TTS عبر HTTP | تسجيل بروتوكول بلا فواصل تحمل إطاراته النظرية PCM16 بتردد 16 kHz؛ ولا يستطيع العميل العام استعادة حدود الإطارات أو صوت قابل للتشغيل |
## تجيب الأدلة والمراجع عن أسئلة مختلفة
| استخدم | عندما تحتاج إلى |
|---|---|
| **دليل API** | اختيار النقل، وتسلسل الطلب، وقواعد دورة الحياة، وتسوية النتائج، والتنظيف، والتنبيهات التشغيلية |
| **مرجع OpenAPI المولد** | مسار HTTP وطريقته ومصادقته ومعاملاته وجسمه وحالاته ومخططات استجابته بدقة |
| **مرجع AsyncAPI المولد** | أسماء أحداث Socket.IO وحقول الحمولات وتخطيطات البايت الثنائية وأمان الاتصال بدقة |
اقرأ الدليل أولاً، ثم أبقِ المرجع المولد المطابق بجانب تنفيذك. إذا بدا أنهما
يختلفان في سلوك البروتوكول المباشر، فعامل المواصفة المولدة المتحقق منها كعقد
وأبلغ عن انحراف الدليل.
## الخطوات التالية
1. [تحقق من العنوان والمفتاح الصادرين](/ar/authentication) بلا رفع صوت.
2. اختر صفًا واحدًا أعلاه وأكمل أصغر طلب ممثل له.
3. أضف معالجة الأخطاء المنظمة وإعادة المحاولة المحدودة من
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
---
# Realtime HTTP
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/realtime-http
عمليات `/realtime/http/*` هي API مباشرة للمنصة. لا يغلفها SDK `0.18.0`.
استخدمها فقط من وقت تشغيل موثوق يستطيع حماية `x-api-key`، وفرض المهل، وتنفيذ
تأطير OpenAPI المتحقق منه.
## 1. اختر العملية وفق دورة حياة الدخل
| الدخل والنتيجة | الاختيار | وحدة الطلب | إشارة الاكتمال |
|----------------|----------|------------|----------------|
| اجتماع أو بودكاست أو أرشيف طويل أو كبير مكتمل | [Batch REST](/ar/api-guides/batch-rest)، وليس عملية Realtime HTTP | ملف مكتمل واحد ثم الاستعلام عن العمل | حالات Batch: `done` أو `failed` أو `cleared` |
| وحدة محادثة واحدة مكتملة حساسة لزمن الاستجابة | `POST /realtime/http/stt` | ملف `multipart/form-data` واحد | استجابة NDJSON من نوع `STTResponse` مع `is_final: true` |
| صوت لا يزال يصل عندما تحتاج نصًا مباشرًا | `POST /realtime/http/stt-stream` | جسم واحد من ترويسة 18 بايت وPCM لكل طلب | يحدد سجل مرصود مع `is_speech_final` حد الكلام، ولا يكمل البث إلا سجل مرصود مع `is_final` |
| صوت لا يزال يصل عندما تحتاج خطًا زمنيًا للمتحدثين | `POST /realtime/http/diarization-stream` | جسم PCM مؤطر واحد لكل طلب متسلسل | سجل مرصود مع `is_final: true`؛ وقد يبقى ذيل مؤقت نشط |
| نص يجب تحويله إلى كلام | TTS عبر Socket.IO في SDK للخرج القابل للتشغيل؛ وHTTP المباشر لتسجيل البروتوكول فقط | طلب JSON واحد | اكتمال SDK؛ ولا يملك HTTP المباشر حد إطار يمكن اكتشافه عمومًا |
يبث النسخ Fast أسطر النتيجة، لكن دخله يظل ملفًا كاملاً واحدًا. وهو ليس وسيلة
نقل لميكروفون مباشر.
## 2. جهّز المصادقة والمعرّفات والمهل
- احصل على `API_URL` و`API_KEY` الخاصين بالبيئة من
[تدفق الوصول الموثق](/ar/authentication). لا تستنتج مضيفًا
من بيئة أخرى.
- أرسل `x-api-key` في كل طلب من خلفية موثوقة. لا تستطيع شيفرة المتصفح أو
الهاتف إبقاء بيانات الاعتماد هذه سرية. يحتاج المفتاح أيضًا إلى القدرة
المخصصة: ASR الفوري لـFast وASR الحي، أو diarization لتدفق المتحدثين، أو TTS
للتوليف.
- أنشئ UUID صالحًا لـ`id`. يضعه Fast STT في الاستعلام، ويضعه TTS في JSON،
وتحمل الإطارات المباشرة بايتاته الخام الستة عشر. لا تعد استخدام UUID واحد
إلا لطلبات البث المباشر نفسه.
- ضع مهلة اتصال، ومهلة محدودة لكل طلب وقراءة، ومهلة كلية للعملية. تحقق من حالة
HTTP قبل تحليل بث النجاح.
- اجمع NDJSON بين قراءات النقل ولا تقسم إلا عند السطر الجديد. قد تحتوي قراءة
شبكة واحدة جزءًا من سطر أو عدة أسطر.
ينطبق `API_PATH` على عملاء Socket.IO ولا تستخدمه مسارات HTTP هذه.
## 3. أرسل وحدة مكتملة واحدة للنسخ Fast
أرسل UUID في `id` وملفًا مكتملاً واحدًا في حقل `file` متعدد الأجزاء. يطبق Fast
اختيار اللغة ونموذج ASR فقط:
| المحدد | القيم المقبولة |
|--------|----------------|
| `language` أو `lang` | `en`، `ar`، `codeswitch`، `auto` |
| `asr` أو `model` | قيمة النموذج المنشورة على البروتوكول |
تسبق قيمة `language` غير الفارغة `lang`، وتسبق قيمة `asr` غير الفارغة
`model`. تستخدم اللغة المحذوفة أو `auto` والنموذج المحذوف إعدادات البيئة
الافتراضية. استخدم Batch عندما تحتاج إلى تمييز المتحدثين أو ITN أو التنقيح.
```bash
export REQUEST_ID="7f51f2c2-e7bc-41c8-a850-f848df2ddfc8"
curl -N --fail-with-body --connect-timeout 10 --max-time 120 \
"${API_URL%/}/realtime/http/stt?id=$REQUEST_ID&language=codeswitch&asr=bayan_cs_ar_en" \
-H "x-api-key: $API_KEY" \
-F "file=@turn.wav"
```
تعيد HTTP `200` النوع `application/x-ndjson`. كل سطر غير فارغ كائن JSON واحد
مكتمل؛ مثلاً:
```json
{"id":"7f51f2c2-e7bc-41c8-a850-f848df2ddfc8","seq":0,"transcription":"hello wor","words":[{"start_time":0.0,"end_time":0.45,"word":"hello"}],"is_final":false}
{"id":"7f51f2c2-e7bc-41c8-a850-f848df2ddfc8","seq":0,"transcription":"hello world","words":[{"start_time":0.0,"end_time":0.45,"word":"hello"},{"start_time":0.46,"end_time":0.9,"word":"world"}],"is_final":true}
```
عالج السجلات بترتيب الوصول المرصود، واحتفظ بـ`seq` للتشخيص فقط؛ فعقد Fast
العام الحالي لا يعرّف لها ترتيبًا أو تفرّدًا. عامل `is_final: false` كحالة
مؤقتة، ولا تنه حالة الطلب إلا بعد `is_final: true`. لا تعامل مقاطع قراءة HTTP
الخام كسجلات، ولا تفترض أن كل نص مؤقت يُلحق بما سبقه.
بعد بدء الناتج الجزئي، ينهي أي إخفاق لاحق بث HTTP `200` الجزئي من دون إلحاق
سجل JSON للخطأ. يكون انتهاء الاستجابة أو الإلغاء أو مهلة التطبيق من دون
`is_final: true` غير مكتمل وملتبس؛ ولا تعرّف العملية عقد إعادة، لذلك لا تعد
إرسال الصوت بلا تمييز.
## 4. أطّر ASR والتمييز المباشرين
تقبل العمليتان المباشرتان `application/octet-stream`. يحمل جسم كل طلب هذا
التخطيط:
استخدم UUID جديدًا غير صفري طوال العملية. اضبط بت البداية في أول طلب، ولا تضبط
أي علم في الطلبات الوسطية، واضبط بت النهاية في آخر طلب؛ واضبط العلمين لتدفق
من مقطع واحد، وأبق البتات المحجوزة صفرًا. يجب أن يحمل كل طلب صوتًا. يمكن إرسال
ملف مؤطر مثل `frame.bin` باستخدام `--data-binary`؛ وهو ليس ملف صوت بمفرده لأنه
يتضمن ترويسة التحكم ذات 18 بايت.
### ابنِ إطارًا صالحًا
تنشئ هذه الأدوات المختبرة افتراضيًا تدفقًا من مقطع واحد، ولذلك تضبط علمي
الحدود معًا. لعدة مقاطع، أعد استخدام `STREAM_ID`، واضبط `IS_FINAL=0` في المقطع
الأول، واضبط العلمين إلى `0` في المقاطع الوسطية، واضبط `IS_FINAL=1` فقط في
المقطع الأخير.
JavaScript / TypeScript
Python
```ts
import { randomUUID } from 'node:crypto';
import { readFile, writeFile } from 'node:fs/promises';
const languageBytes = {
ar: 0,
en: 1,
codeswitch: 2,
auto: 255,
} as const;
function uuidBytes(id: string): Uint8Array {
const hex = id.replaceAll('-', '');
if (!/^[0-9a-f]{32}$/i.test(hex) || /^0{32}$/.test(hex)) {
throw new Error('STREAM_ID must be a nonzero UUID');
}
return Uint8Array.from(hex.match(/.{2}/g)!, (byte) => Number.parseInt(byte, 16));
}
function frame(
id: string,
pcm16le: Uint8Array,
options: { language: keyof typeof languageBytes; isStart: boolean; isFinal: boolean },
): Uint8Array {
if (pcm16le.byteLength === 0 || pcm16le.byteLength % 2 !== 0) {
throw new Error('PCM16 payload must be nonempty and contain an even number of bytes');
}
const output = new Uint8Array(18 + pcm16le.byteLength);
output.set(uuidBytes(id), 0);
output[16] = (options.isStart ? 1 : 0) | (options.isFinal ? 2 : 0);
output[17] = languageBytes[options.language];
output.set(pcm16le, 18);
return output;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'chunk.pcm';
const outputPath = process.argv[3] ?? 'frame.bin';
const streamId = process.env.STREAM_ID ?? randomUUID();
const pcm = await readFile(inputPath);
// Defaults build a valid one-chunk stream. For a longer stream, reuse
// STREAM_ID and set only the boundary flags for each arriving PCM chunk.
const body = frame(streamId, pcm, {
language: 'codeswitch',
isStart: process.env.IS_START !== '0',
isFinal: process.env.IS_FINAL !== '0',
});
await writeFile(outputPath, body);
console.info({ streamId, bytes: body.byteLength, outputPath });
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import os
import sys
import uuid
from pathlib import Path
LANGUAGE_BYTES = {
"ar": 0,
"en": 1,
"codeswitch": 2,
"auto": 255,
}
def build_frame(
stream_id: uuid.UUID,
pcm16le: bytes,
*,
language: str,
is_start: bool,
is_final: bool,
) -> bytes:
if stream_id.int == 0:
raise ValueError("STREAM_ID must be a nonzero UUID")
if not pcm16le or len(pcm16le) % 2:
raise ValueError(
"PCM16 payload must be nonempty and contain an even number of bytes"
)
flags = (1 if is_start else 0) | (2 if is_final else 0)
return stream_id.bytes + bytes((flags, LANGUAGE_BYTES[language])) + pcm16le
def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "chunk.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "frame.bin")
stream_id = uuid.UUID(os.environ.get("STREAM_ID", str(uuid.uuid4())))
# Defaults build a valid one-chunk stream. For a longer stream, reuse
# STREAM_ID and set only the boundary flags for each arriving PCM chunk.
body = build_frame(
stream_id,
input_path.read_bytes(),
language="codeswitch",
is_start=os.environ.get("IS_START", "1") != "0",
is_final=os.environ.get("IS_FINAL", "1") != "0",
)
output_path.write_bytes(body)
print({"stream_id": str(stream_id), "bytes": len(body), "output": str(output_path)})
if __name__ == "__main__":
main()
```
### ASR المباشر
```bash
curl -N --fail-with-body --connect-timeout 10 --max-time 30 \
-X POST "${API_URL%/}/realtime/http/stt-stream" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/octet-stream" \
--data-binary @frame.bin
```
أرسل طلب POST واحدًا لكل مقطع صوت مؤطر. تحتوي كل استجابة HTTP `200` صفرًا أو
أكثر من سجلات NDJSON ذات `id` و`seq` و`transcription` و`words` و
`is_speech_final` و`is_final`. وينهي أي فشل لاحق بث `200` الجزئي من دون إلحاق
سجل خطأ. اجمع البيانات عبر القراءات وحلل الأسطر المكتملة. يحدد
`is_speech_final` حد مقطع كلام مكتشفًا؛
ولا يكمل البث كله إلا سجل مرصود مع `is_final: true`. لا يثبته علم النهاية في
الطلب ولا انتهاء الاستجابة، بما في ذلك `200` فارغة. عامل `seq` كقيمة معتمة،
ووفّق النص المؤقت باستخدام `id` وترتيب الوصول المرصود كما هو موضح في
[دليل دورة حياة Realtime](/ar/api-guides/realtime).
لا يعرّف العقد العام ما إذا كان ينبغي تداخل طلبات POST للمقاطع أو إرسالها
تتابعيًا. استخدم فقط نمط التنسيق المخصص لبيئتك، ولا تستنتج أمان التوجيه من
تزامن HTTP العادي.
تنتهي نافذة الاستجابة العادية غير النهائية بعد ثانيتين مع الحفاظ على الجلسة.
ويلغي إجهاض طلب POST أو انقضاء مهلة الاستجابة النهائية الجلسة. كما تنتهي
صلاحيتها بعد 60 ثانية من دون صوت عميل مقبول أو استجابة من محرك الاستدلال.
المسار `POST /realtime/http/realtime-asr` مسار توافقي. ينبغي للعملاء الجدد
استخدام العملية الأساسية `POST /realtime/http/stt-stream`.
### التمييز المباشر
```bash
curl -N --fail-with-body --connect-timeout 10 --max-time 30 \
-X POST "$API_URL/realtime/http/diarization-stream" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/octet-stream" \
--data-binary @frame.bin
```
ليس لهذه العملية معاملات استعلام أو نموذج متعدد الأجزاء أو محدد نموذج من
العميل. يجب أن يكون بايت اللغة `0` أو `1` أو `2` أو `255`، لكن الخدمة تتجاهله
بعد التحقق. ضع علم النهاية على آخر إطار صوت حقيقي لأن إطار الإنهاء الفارغ غير
صالح. يعيد بث لم يستقبل إطار بدء حالة HTTP `400` مع
`VALIDATION_REQUIRED_FIELD`.
لا تُبقِ أكثر من طلب POST واحد قيد التنفيذ لكل UUID. التقط الصوت بالتزامن في
طابور محدود، لكن استخدم مرسلاً واحدًا لتفريغه وإغلاق كل استجابة قبل إرسال
الإطار التالي. قد تستبدل الطلبات المتزامنة للـUUID نفسه ملكية الاستجابة؛ ويمكن
تشغيل تدفقات UUID المختلفة بالتزامن.
تحتوي كل استجابة HTTP `200` صفرًا أو أكثر من سجلات NDJSON ذات `id` و
`final_segments` و`active_segments` و`is_final`. وينهي أي فشل لاحق بث `200`
الجزئي من دون إلحاق سجل خطأ. اجمع إضافات `final_segments` غير المشاهدة لأن كل
مصفوفة إضافة خاصة بالسجل. استبدل
لقطة `active_segments` السابقة، ثم رتب الخط الزمني الموفق من المقاطع النهائية
والنشطة حسب `start_time`. تسميات المتحدثين نسبية لتدفق واحد وليست هويات،
والأزمنة نسبية إلى بدايته.
لا يكمل التدفق إلا سجل مرصود مع `is_final: true`. لا يثبته علم النهاية في
الطلب ولا `200` فارغة ولا EOF ولا مهلة الاستجابة. قد يحتفظ السجل النهائي بذيل
نشط غير فارغ؛ أبقه مؤقتًا ولا تحوله ضمنيًا إلى نهائي. تنتهي نافذة الاستجابة
العادية غير النهائية بعد ثانيتين مع الحفاظ على الجلسة. ويلغي إجهاض طلب POST أو
انقضاء مهلة الاستجابة النهائية الجلسة، وتنتهي صلاحيتها بعد 60 ثانية من دون
نشاط العميل أو محرك الاستدلال. لا يوجد عقد لإعادة المقاطع أو الاستئناف أو
idempotency. بعد فشل ملتبس، أغلق كل الاستجابات وعلّم الخط الزمني غير مكتمل
وتعافَ بـUUID جديد بدلاً من إعادة مقطع قديم.
## 5. اطلب TTS عبر HTTP مع مراعاة عقد الخرج
يتطلب جسم JSON قيمة `id` جديدة ونص `text` يحتوي بعد إزالة الفراغات على حرف
Unicode أو رقم واحد على الأقل. الحقول الاختيارية هي
`model` و`voice_id` و`voice_references`.
لاختيار صوت متوقع، أرسل `voice_id` واحدًا بصيغة UUID أو مرجعًا واحدًا يكون
`audio` فيه RIFF/WAVE بترميز base64 القياسي مع بيانات PCM16 أحادية غير فارغة،
ويكون `text` نصه. المحددان متنافيان. احصل على `voice_id` عبر `listVoices()` أو
`list_voices()` في SDK؛ ولا توجد عملية HTTP لسرد الأصوات. اضبط `model` على
`nebula` صراحة بدل الاعتماد على افتراضي النشر، الذي يرجع إلى `nebula` عند
غيابه.
```bash
curl --fail-with-body --connect-timeout 10 --max-time 120 \
-X POST "$API_URL/realtime/http/tts" \
-H "x-api-key: $API_KEY" \
-H "content-type: application/json" \
--data '{"id":"7f51f2c2-e7bc-41c8-a850-f848df2ddfc8","text":"Hello from HUMAIN Voice","model":"nebula"}' \
--output tts-frames.bin
```
تعيد HTTP `200` جسمًا متصلاً من النوع `application/octet-stream`:
تلحق الخدمة إطارًا نهائيًا حتى عندما لا يحمل ذلك الإطار PCM إضافيًا. لا يعرّف
العقد طول إطار أو فاصلاً. مقاطع قارئ HTTP هي مقاطع نقل ولا يُضمن تطابقها مع
حدود إطارات الخدمة، لذلك لا يمكن لعميل عام إزالة 17 بايت من كل قراءة بأمان.
الملف `tts-frames.bin` في المثال تسجيل للبروتوكول، وليس ملف PCM أو WAV قابلاً
للتشغيل.
إذا فشل التوليف بعد إرسال بايتات، فإن تدفق `200` الثنائي الجزئي ينتهي فقط: ولا
تُلحق أي بيانات JSON منظمة للخطأ. لذلك يترك غياب العلم النهائي القابل لتمييز
الحدود أو EOF مبكر أو انتهاء المهلة تسجيلًا غير مكتمل بلا تفسير داخل القناة، ولا
يمكن الإبلاغ بـJSON منظم إلا عن فشل يحدث قبل تثبيت الخرج. ويلغي إجهاض طلب HTTP
التوليف الجاري له وحده. تُبلَّغ أخطاء
النموذج والسعة والاستدلال في عملية HTTP المباشرة بالحالة `500 TTS_SYNTHESIS_FAILED`
القابلة للإعادة؛ وقد تعيد البوابة `429` بصورة مستقلة. رفض سياسة المحتوى هو
`400 TTS_INPUT_NOT_ALLOWED` غير قابل للإعادة؛ غيّر النص بدل إعادة إرساله. وإذا
تعذر على جهة الإشراف اتخاذ قرار، يفشل التوليف بصورة مغلقة مع
`503 TTS_MODERATION_UNAVAILABLE` القابل للإعادة؛ فلا تبلغ عن فشل البنية التحتية
هذا بوصفه محتوى محظورًا. ولم يعد `voice_id` المُرسَل من العميل يُطوى في
`TTS_SYNTHESIS_FAILED` (SAU-2258): فـ`voice_id` غير القابل للتحليل هو
`400 VALIDATION_INVALID_UUID`، و`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا هو
`400 TTS_VOICE_NOT_FOUND` (كلاهما غير قابل للإعادة)؛ وصوت محلول بياناته المخزَّنة
ناقصة أو تالفة هو `500 TTS_VOICE_RESOLUTION_FAILED` (غير قابل للإعادة)؛ وانقطاع
عابر لقاعدة البيانات/التخزين أثناء حل الصوت هو `503 SERVER_DEPENDENCY_FAILURE`
(قابل للإعادة).
لم تعد مشكلات النص ومرجع الصوت تُطوى بهذه الطريقة. فالنص الذي يتجاوز الحد، ونص
المرجع الذي يتجاوز حده، وأكثر من مرجع واحد، ومقطع المرجع الأطول من حد المرجع
المضبوط في النشر، كلها `422` غير قابلة للإعادة؛ والمرجع الذي يتجاوز حجمه المفكوك الحد هو
`413`؛ وأما المرجع المشوه أو إرسال المحددين معًا أو مصفوفة `voice_references`
الفارغة الصريحة فهي `400` غير قابلة للإعادة. ويتم التحقق من جميعها قبل أي بحث عن
النموذج أو قبول أو محاسبة، ويحمل كل رفض للحد كائن `data` يسمي الحد وقيمته
المضبوطة والقيمة المرصودة. راجع
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
إلى أن يملك عميلك المباشر آلية غير ملتبسة لحدود الإطارات، استخدم TTS عبر
Socket.IO في SDK و[وصفة TTS إلى WAV](/ar/recipes/text-to-speech-to-file) لخرج
قابل للتشغيل. لا تفترض صيغة خرج Socket.IO ذات 24 kHz لهذه العملية عبر HTTP ذات
16 kHz.
## 6. قيّد حالات الفشل ونظّف كل بث
1. تحقق من حالة HTTP قبل اختيار محلل نجاح NDJSON أو الثنائي. قد تعيد بوابة
النشر `429`، بينما قد تطوي الخلفيات الحالية فشل السعة إلى `500` قابلة
للإعادة مع `ASR_TRANSCRIPTION_FAILED` أو `DIARIZATION_FAILED` أو
`TTS_SYNTHESIS_FAILED`. عامل حالة كل طبقة وجسمها كدليل، ولا تستنتج حصة
رقمية أو نافذة إعادة ضبط.
2. في `ErrorResponse`، اتخذ القرار من `code` و`retryable` لا من صياغة `error`
أو `detail` أو `message`.
3. عند فشل بث مباشر أو انتهاء مهلته، أوقف إرسال الإطارات، وألغِ الطلب، وأغلق
قارئ استجابته، وابدأ التعافي بـUUID جديد. استئناف الجلسة بعد الانقطاع غير
موثق.
4. تكون المهلة بعد إرسال الملف متعدد الأجزاء الكامل ملتبسة. لا يعرّف العقد
إعادة idempotent، لذلك لا تكرر الطلب بلا تمييز.
5. إذا انتهى عميل TTS القادر على تمييز الحدود من دون إطار نهائي، فافصل
البايتات الجزئية عن الخرج المكتمل وأغلق الاستجابة. لا تستنتج الاكتمال من
إغلاق الاتصال وحده.
طبّق إعادة محاولة محدودة فقط عندما يسمح الخطأ المنظم بذلك، وتكون العملية آمنة
وفق سياسة تطبيقك، وتبقى المهلة الكلية. راجع
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
## 7. انتقل إلى العقد وتحققات الإنتاج
ابدأ بأصغر طلب ممثل للعملية المختارة، وتحقق من إشارتها النهائية الموثقة. أبق
مرجع OpenAPI المولد بجانب تنفيذك للمعاملات والمخططات والأخطاء الدقيقة، ثم اختبر
المهل، والإطارات غير الصالحة، والانقطاعات، والتنظيف قبل الإطلاق.
---
# نظرة عامة على Realtime
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/realtime
يعني Realtime أن الصوت لا يزال يصل عند بدء النسخ أو التمييز. لا تجعل استجابة
متدفقة الملف المرفوع المكتمل Realtime.
## 1. اختر وفق دورة حياة المصدر
| حالة المصدر عند بدء المعالجة | الاختيار | العقد |
|------------------------------|----------|-------|
| اجتماع أو بودكاست أو أرشيف طويل أو كبير مكتمل | [Batch REST](/ar/api-guides/batch-rest) | ارفع مرة، واستلم `jobId`، واستعلم عن عمل |
| وحدة محادثة واحدة مكتملة حساسة لزمن الاستجابة | النسخ Fast عبر `audio_file` في Socket.IO أو HTTP `POST /realtime/http/stt` | أرسل الوحدة كلها، وأنهِ عند `is_final: true` |
| صوت لا يزال يصل من ميكروفون أو مكالمة أو مصدر مباشر | ASR أو التمييز عبر Realtime | أرسل PCM مؤطرًا عند وصوله، ووفّق الحالة المؤقتة والنهائية |
يمكن لـTTS بث الخرج المولد، لكنه ليس دورة حياة دخل الصوت المباشر المعرّفة هنا.
راجع أدلة النقل العملية لسلوك TTS.
## 2. اختر وسيلة النقل المباشر
| الجانب | Socket.IO مع SDK `0.18.0` | HTTP المؤطر المباشر |
|--------|----------------------------|---------------------|
| الغلاف المنشور | JavaScript وPython | لا يوجد |
| الإعداد | `API_URL` و`API_KEY`؛ ويستخدم SDK `/socket.io` افتراضيًا | `API_URL` و`API_KEY`؛ من دون مسار Socket.IO |
| دخل ASR المباشر | يرسل بث SDK الحدث `audio_stream` | طلب `POST /realtime/http/stt-stream` واحد لكل مقطع مؤطر |
| دخل التمييز المباشر | يرسل بث SDK الحدث `diarization_stream` | طلب `POST /realtime/http/diarization-stream` واحد لكل مقطع مؤطر |
| النتائج | الحدثان `transcription_result` و`diarization_result` | سجلات استجابة `application/x-ndjson` |
| مالك التأطير | ينشئ SDK الإطارات ويوجهها حسب UUID | ينشئ التطبيق كل ترويسة 18 بايت ويعيد استخدام UUID |
| مالك التنظيف | أغلق البث ثم افصل العميل | أرسل إطارًا نهائيًا، وأنهِ القراءات أو أوقفها، وأغلق أجسام الاستجابة |
استخدم نقل SDK عندما يدعم وقت التشغيل Socket.IO. استخدم HTTP المباشر عندما لا
يستطيع وقت التشغيل الموثوق استخدام Socket.IO ويمكنه تنفيذ عقد التأطير
والاستجابة الدقيق بنفسه.
تتطلب وسيلتا النقل المباشر `x-api-key` وصوت PCM16 little-endian بتردد 16 kHz
وأحادي القناة. ابدأهما من خلفية موثوقة. يحتوي كل إطار دخل 16 بايت UUID خامًا،
وبايت أعلام، وبايت لغة، ثم PCM. تعرض أدلة النقل العملية أدناه التخطيط الدقيق.
## 3. أنشئ سجل حالة واحدًا لكل بث
قبل إرسال الصوت، أنشئ UUID جديدًا وسجل حالة يملكه التطبيق لذلك البث. تتبع:
- `id` للبث وعداد وصول يعينه التطبيق؛
- نصًا مؤقتًا واحدًا قابلاً للاستبدال؛
- كلمات الأحداث النهائية المثبتة بترتيب الوصول المرصود؛
- وصول إشارات speech-final وstream-final؛
- مقاطع التمييز المغلقة والنشطة؛
- أول خطأ منظم والمهلة الكلية.
افصل هذه الحالة عن المقبس أو قارئ HTTP. يجب ألا يمحو إغلاق النقل النص المثبت،
ويجب ألا تستبدل استجابة مؤقتة متأخرة حالة أحدث أو نهائية.
## 4. وفّق ترتيب وصول ASR ونهائيته
تتضمن الاستجابة `seq`، لكن عقد Realtime العام الحالي لا يعرّف دلالات ترتيب أو
تفرّد لها. عيّن رقم وصول محليًا، وتحقق من علمي النهائية في كل استجابة، وطبق
التغييرات التالية:
| الإشارة | المعنى | إجراء الحالة |
|---------|--------|---------------|
| وصول حدث نتيجة | حالة مرصودة جديدة | سجل رقم وصول محليًا، وأبقِ `seq` القادمة من الخادم لبيانات التشخيص فقط |
| `is_final: false` و`is_speech_final: false` | نص مؤقت | استبدل العرض المؤقت الحالي |
| `is_speech_final: true` | اكتشف النموذج حد نهاية كلام | ثبّت كلمات ذلك الحدث بترتيب الوصول، ثم امسح القيمة المؤقتة التي حلت محلها بينما يمكن أن يستمر البث |
| `is_final: true` | النتيجة النهائية لبث النسخ | ثبّت ذلك الحدث مرة، وامسح النص المؤقت الذي حل محله، وعلّم نتيجة البث كطرفية |
عندما يكون علما النهائية true في استجابة واحدة، ثبّتها مرة وسجل الحقيقتين. لا
تستنتج أي علم من فترة هدوء أو اتصال مغلق أو اكتمال استدعاء `close()`.
أنشئ `SRT` أو `WebVTT` من توقيت الكلمات النهائية فقط. يزيل
`RealtimeSubtitles` التكرار حسب `id:seq`، ولذلك قد يدمج أحداثًا نهائية متميزة
ما دام الخادم يرسل قيم `seq` غير متميزة. لهذا العقد، اجمع الكلمات النهائية
بترتيب الوصول المرصود واعرضها باستخدام `Subtitles`.
## 5. وفّق التمييز كخط زمني متطور
لكل سجل `diarization_result` أو سجل تمييز عبر HTTP:
1. احتفظ بـ`final_segments` وأزل تكرارها؛ فهذه المقاطع المغلقة لا تتغير.
2. استبدل مجموعة `active_segments` السابقة بأحدث مجموعة؛ فقد تتطور هذه المقاطع
أو تصبح نهائية.
3. عامل `is_final: true` كآخر استجابة لبث التمييز ذلك.
4. وفّق أحدث خط زمني للمتحدثين مع توقيت الكلمات النهائية باستخدام قاعدة تداخل
صريحة.
تمثل تسميات المتحدثين أدوارًا نسبية في هذا البث، لا هوية حقيقية.
## 6. أنهِ البث بمهل منفصلة وتنظيف صريح
استخدم مهلاً منفصلة محدودة للاتصال، والجلسة كلها، وكل إرسال أو قراءة، وانتظار
النتيجة النهائية. ثم أنهِ بهذا الترتيب:
1. أوقف منتج الصوت حتى لا يضيف PCM جديدًا إلى الطابور.
2. أرسل إطار النهاية الموثق مرة واحدة بالضبط.
3. انتظر فقط حتى مهلة النتيجة النهائية لإشارة النهائية المناسبة.
4. سجل هل اكتمل الإنهاء أم انتهت مهلته أم فشل.
5. حرر وسيلة النقل في كتلة `finally` أو سياق async.
في Realtime ASR ضمن SDK `0.18.0`، يرسل
`stream.close(timeoutSeconds)` في JavaScript و
`stream.close(timeout_seconds=...)` في Python إطار النهاية، وينتظران حالة
`is_final` على مستوى البروتوكول أو خطأ موجهًا أو المهلة المحددة. ويعودان عند
انتهاء الانتظار بدلاً من إطلاق خطأ مهلة. لا يثبت ذلك العود وصول `is_final`؛
افحص الحالة التي سجلتها الاستدعاءات. أما `is_speech_final` فهو حد كلام فقط ولا
ينهي انتظار الإغلاق. ويعيد مساعد التمييز كذلك أفضل خط زمني معروف إذا انتهت
مهلة الانتظار النهائي.
بعد إنهاء البث، يجب أن تستدعي JavaScript الدالة `disconnect()` داخل `finally`؛
ويجب أن تخرج Python من سياق العميل غير المتزامن. في HTTP المباشر، ألغِ الطلب
المنتهية مهلته وأغلق قارئ استجابته.
## 7. عامل نتيجة الانقطاع كحالة ملتبسة
لا تعرّف العقود العامة استئناف الجلسة ولا إعادة idempotent لإطارات الصوت. كما
لا تضمن حالة الخادم التي تبقى بعد سقوط اتصال Socket.IO أو انقطاع طلب HTTP.
تعافَ عبر حد بث جديد:
1. أوقف تغذية البث القديم وأغلق وسيلة نقله.
2. احتفظ بالنتائج المثبتة، وتجاهل النص المؤقت غير المحسوم، وعلّم فترة الصوت
الملتبسة.
3. لا تعد المحاولة إلا إذا سمح الخطأ المنظم وسياسة التطبيق بذلك وبقيت المهلة
الكلية؛ قيّد التراجع وjitter وعدد المحاولات والزمن المنقضي.
4. أعد الاتصال بـUUID جديد وأرسل إطار بدء جديدًا.
5. افصل نتائج البث الجديد حتى يضم التطبيق الخطين الزمنيين المثبتين صراحة.
لا تعد استخدام UUID القديم أو تعيد الإطارات بافتراض إزالة الخادم لتكرارها.
إذا احتفظ التطبيق بصوت الفترة الملتبسة، فعالجه عبر مسار تعافٍ صريح بدلاً من
وصله صامتًا بالبث المباشر الجديد. راجع
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
## 8. انتقل إلى وسيلة نقل ومرجع ووصفة
اختر وسيلة نقل واحدة، وشغّل أصغر بث مباشر ممثل لها، وتحقق من إشارة النهائية
الصحيحة، واختبر مساري المهلة والانقطاع قبل الإنتاج.
---
# واجهة Socket.IO
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/socketio
استخدم هذا الدليل لدورة حياة Socket.IO: اختر قدرة، واتصل، وسجل أقل مجموعة
أحداث، وتعرف على إشارتها النهائية، وافصل دائمًا. استخدم صفحات AsyncAPI
المولدة لمخططات الحمولات الكاملة.
في تطبيقات JavaScript وPython، فضّل SDK `0.18.0`؛ فهو ينشئ الإطارات الثنائية،
ويوجه UUID، ويطبع الأخطاء، ويوفر مساعدي الإغلاق. ابنِ عميلًا مباشرًا فقط
عندما تحتاج إلى تحكم على مستوى السلك.
## اختر سير العمل
| الدخل المتاح | اختر | إشارة الاكتمال |
|---|---|---|
| وحدة صوت مكتملة وقصيرة وحساسة لزمن الوصول، مثل دور في محادثة وكيل صوتي | النسخ السريع | `transcription_result.is_final === true` |
| صوت PCM ما زال يصل ويحتاج إلى نص | Realtime ASR | نهاية السلك: `is_final === true`؛ وحد الكلام: `is_speech_final === true` |
| صوت PCM ما زال يصل ويحتاج إلى أدوار المتحدثين | التمييز المباشر | إطار دخل نهائي، ثم `diarization_result.is_final === true` أو مهلة التطبيق |
| نص يحتاج إلى كلام مولد | اكتشاف الأصوات، ثم TTS | بت النهاية في إطار `tts_audio` |
يستقبل النسخ السريع الحمولة المكتملة مرة واحدة. وهو ليس مسار الاجتماعات أو
البودكاست أو المواد الأرشيفية الطويلة؛ استخدم النسخ الدفعي لهذه التسجيلات
المكتملة.
## متطلبات الاتصال
- `API_URL` و`API_KEY` الصادرتان للبيئة. ويضبط عميل Socket.IO المباشر المسار
على `/socket.io` أيضًا.
- عميل Socket.IO على الخادم. أبقِ `API_KEY` خارج حزم المتصفح والجوال.
- اضبط `transports: ["websocket"]` لعقد النقل المنشور والقابل للنقل بين
البيئات. قد توجه بعض البيئات polling، لكن يجب ألا يعتمد العميل عليه.
- أرسل `x-api-key` و`Origin` كترويستي اتصال. يشغّل طرف الإنتاج جدار حماية
لتطبيقات الويب يرفض أي مصافحة بلا `Origin`؛ اضبطها على مخطط `API_URL` ومضيفه.
- تسجيل معالجات الأحداث قبل الاتصال أو قبل إرسال طلب.
- مهلة تطبيق إجمالية لكل طلب أو تدفق.
أبقِ المسار صريحًا في عملاء Socket.IO المباشرين. يستخدم SDK `0.18.0` المسار
`/socket.io` افتراضيًا؛ ولا تمرر `api_path` إلا عندما يستخدم النشر مسارًا
مخصصًا. تتطلب نقطة النهاية القديمة `sautech.humain.com` المسار
`/realtime/socket.io`.
## اتصل مرة واحدة ثم افصل
يمكن لاتصال واحد مضاعفة عدة طلبات أو تدفقات. أعطِ كلًا منها UUID ووجّه كل
استجابة حسب `id` قبل معالجتها.
JavaScript / TypeScript
Python
```ts
import { io } from "socket.io-client";
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!,
},
});
try {
// Register handlers, wait for connect, and run one or more operations.
} finally {
socket.disconnect();
}
```
```python
import asyncio
import os
import socketio
API_URL = os.environ["API_URL"]
API_KEY = os.environ["API_KEY"]
async def main() -> None:
sio = socketio.AsyncClient()
try:
await sio.connect(
API_URL,
headers={"x-api-key": API_KEY, "Origin": API_URL},
socketio_path=os.environ.get("API_PATH", "/socket.io"),
transports=["websocket"],
)
# Register handlers before connect in real code, then run operations.
finally:
if sio.connected:
await sio.disconnect()
asyncio.run(main())
```
**النتيجة المتوقعة:** يستدعي العميل معالج نجاح الاتصال قبل إرسال أي طلب
للتطبيق. تعامل مع فشل الاتصال كنهاية لهذه المحاولة ونظّف قبل إعادة المحاولة.
في `python-socketio`، يكون `transports` معاملًا لـ`connect()`، وليس لمُنشئ
`AsyncClient`.
## النسخ السريع لوحدة صوت مكتملة
يقبل النسخ السريع حمولة AAC أو FLAC أو MP3 أو MP4 أو WAV مكتملة. يجب أن تكون
ذرة `moov` في مقدمة MP4. أرسل ثنائيًا خامًا، لا JSON أو base64.
أقل تسلسل للأحداث:
1. سجل `audio_file_upload_success` و`transcription_result` و`error`.
2. أرسل حزمة `audio_file` ثنائية واحدة.
3. طابق `audio_file_upload_success.id` مع UUID الطلب؛ فهذا يؤكد الاستلام ولا
يعني اكتمال النسخ.
4. وجّه أحداث النتائج حسب `id`، وعامل `seq` كقيمة مبهمة لأن عقد Fast العام لا
يعرّف دلالات ترتيب أو تجميع لها. أنهِ الانتظار فقط عندما تصبح `is_final`
صحيحة.
5. احتفظ بالاتصال أو أعد استخدامه فقط ضمن مهلة تطبيق؛ وإلا فافصل.
تملك حزمة `audio_file` هذا التخطيط المتغير الطول الدقيق:
| الإزاحة | الحجم | الحقل |
|---|---:|---|
| `0..15` | 16 بايت | UUID الطلب |
| `16` | 1 بايت | اللغة: `0` للعربية، `1` للإنجليزية، `2` لتبديل اللغتين، `255` للتلقائي |
| `17..18` | 2 بايت | طول `asr_model_key` بالبايت، عدد صحيح 16 بت little-endian بلا إشارة |
| `N` التالية | `N` بايت | `asr_model_key` بترميز UTF-8؛ يختار الطول صفر افتراضي اللغة |
| 2 التالية | 2 بايت | طول `dia_model_key` بالبايت، عدد صحيح 16 بت little-endian بلا إشارة |
| `N` التالية | `N` بايت | `dia_model_key` محجوز؛ أرسل طولًا صفريًا |
| 2 + `N` التالية | متغير | `itn_model_key` محجوز مسبوق بطوله؛ أرسل طولًا صفريًا |
| 2 + `N` التالية | متغير | `redact_model_key` محجوز مسبوق بطوله؛ أرسل طولًا صفريًا |
| الباقي | متغير | بايتات ملف الصوت المشفر المكتمل |
يسلسل SDK `0.18.0` حقول التوافق الثلاثة المحجوزة، لكن خدمة Fast العامة المتحقق
منها لا تطبقها. استخدم Batch عندما تحتاج إلى التمييز أو ITN أو الإخفاء.
لا يملك JavaScript SDK `0.18.0` خيار مهلة للنسخ السريع. يستدعي خطأ الطلب
الموجه `onError` ثم يرفض بـ`Error` عام يحتفظ بالرسالة فقط. لا تعد إرسال رفع
ملتبس بلا تمييز؛ فلا يوجد عقد idempotency-key منشور.
## تأطير Realtime ASR ودورة حياته
يحمل `audio_stream` عينات PCM16 little-endian بتردد 16 kHz وأحادية القناة.
أعد استخدام UUID واحد للتدفق كله.
أقل تسلسل للأحداث:
1. سجل `transcription_result` و`diarization_result` الاختياري و`error`.
2. أرسل إطار بداية واحدًا بالضبط وبايت رايات `1`.
3. أرسل إطارات وسطية وبايت رايات `0`.
4. أرسل إطار نهاية واحدًا بالضبط وبايت رايات `2`.
5. وجّه النص حسب `id` وترتيب الوصول المرصود. أبقِ `seq` القادمة من الخادم
للتشخيص فقط لأن ترتيبها وتفرّدها ليسا ضمانين عامين. استبدل النص المؤقت ما
دامت رايتا النهاية خاطئتين، وثبّت كلمات الحدث مرة واحدة عندما تصبح
`is_final` أو `is_speech_final` صحيحة.
6. بعد الدخل النهائي، ينتظر العميل المباشر `is_final: true` حتى مهلة
التطبيق. وينتظر مساعد `close()` في SDK المنشور `is_final` نفسها على مستوى
البروتوكول أو خطأ موجهًا أو انتهاء مهلته المحدودة. لا تنهي
`is_speech_final` ذلك الانتظار. افحص حالة الاستجابة؛ فقد يعني العود الناجح
انتهاء المهلة ولا يثبت النهائية وحده.
ترسل وصفة SDK المختبرة 3,200 بايت صوت، أي 100 ms، في كل إطار. هذا إيقاع
عملي وليس ضمانًا للإنتاجية أو زمن الوصول. اضبط البت 2 في بايت الرايات فقط
عندما تريد أيضًا أحداث `diarization_result` على الاتصال نفسه.
## تأطير التمييز المباشر ودورة حياته
يستخدم `diarization_stream` تخطيط الإطار ذي 18 بايت وصيغة PCM المطلوبين
نفسيهما في `audio_stream`. تستخدم راياته البت 0 للبداية والبت 1 للنهاية؛
وأبقِ البتات الأخرى صفرًا.
أقل تسلسل للأحداث:
1. سجل `diarization_result` و`error`.
2. أرسل إطار بداية، ثم إطارات وسطية، ثم إطار نهاية تحت UUID نفسه.
3. اجمع إضافات `final_segments` غير المشاهدة واستبدل ذيل
`active_segments` الحالي في كل نتيجة.
4. تعامل مع `is_final: true` كإشارة الخادم النهائية. إذا انتهت المهلة أولًا،
فأعد أفضل خط زمني موفق معروف بوصفه غير مكتمل.
5. افصل أثناء التنظيف.
يوصي مساعد SDK الصادر بـ15,360 بايت صوت لكل تغذية. استهلك النتائج أثناء
الإرسال؛ فقد يعلق المسار إذا أخّرت الاستهلاك إلى ما بعد انتهاء التغذية. يعيد
SDK `close(5)` أفضل خط زمني معروف عند انتهاء مهلة انتظاره النهائي.
## اكتشاف الأصوات ودورة حياة TTS
اكتشف صوتًا بدل تخمين معرّفه:
1. سجل `tts_voice_list_result` و`error`.
2. أرسل `tts_voice_list` مع `{}`.
3. تعامل مع الاستجابة كمصفوفة `{ id, label }`؛ وتعامل مع المصفوفة الفارغة.
ثم ولّد الكلام:
1. سجل `tts_audio` و`error`.
2. أرسل `tts` مع `id` ونص `text` يحتوي بعد إزالة الفراغات على حرف Unicode أو
رقم واحد على الأقل، و`model: "nebula"` صريح.
3. لاختيار صوت متوقع، أرسل إما `voice_id` من الاكتشاف أو عنصر
`voice_references` واحدًا بشكل `{ audio, text }`. يكون `audio` فيه RIFF/WAVE
بترميز base64 القياسي وبيانات PCM16 أحادية غير فارغة. المحددان متنافيان.
4. طابق كل استجابة ثنائية حسب UUID الطلب، وألحق البايتات `17..end`، وتوقف
عند ضبط البت 0 في البايت `16`.
بت النهاية هو إشارة اكتمال TTS. حلل كل حدث `tts_audio` بترويسة التطبيق هذه،
ولا تلحق أول 17 بايت منه. استخدم
[وصفة TTS إلى WAV المختبرة](/ar/recipes/text-to-speech-to-file) لإنشاء ملف
قابل للتشغيل. يؤدي فصل الاتصال إلى إلغاء طلبات التوليف النشطة التي يملكها ذلك
الاتصال ومنع أحداث الصوت والخطأ اللاحقة، من دون إغلاق اتصالات الاستدلال
المشتركة مع طلبات أخرى.
## الأخطاء المنظمة والمهل والإنهاء
تعرف عقود الأحداث المولدة كائنات `error` تحتوي الحقول المطلوبة `code` و
`message` و`retryable` و`timestamp`، إضافة إلى `id` الطلب عندما يمكن توجيه
الحمولة. سجل معالجة الأخطاء الخاصة بالطلب والعامة معًا.
| القدرة | الإشارة النهائية | قاعدة المهلة والتنظيف |
|---|---|---|
| النسخ السريع | `is_final: true` | لا مهلة في JavaScript SDK؛ ضع حدًا للطلب كله وأغلق العميل |
| Realtime ASR | إشارة النهاية على السلك وفي إغلاق SDK: `is_final: true` | قد يعني عود إغلاق SDK انتهاء مهلته؛ افحص النهائية المتعقبة وافصل دائمًا داخل `finally` |
| التمييز المباشر | إطار دخل نهائي، ثم `is_final: true` | عند انتهاء مهلة الإغلاق، احتفظ بأفضل خط زمني معروف ووسمه غير مكتمل |
| اكتشاف الأصوات | استجابة `tts_voice_list_result` واحدة يمكن أن تكون فارغة | ضع حدًا للانتظار؛ ولا تخترع معرّف صوت |
| TTS | ضبط البت 0 في ترويسة `tts_audio` | مهل SDK ضوابط للعميل؛ ويفرض الخادم أيضًا مهلة كلية غير قابلة لإعادة الضبط قدرها 25 ثانية ومراقب خمول قدره 60 ثانية. ويلغي الفصل طلبات ذلك الاتصال النشطة. |
يطبع SDK `0.18.0` الاستدعاءات المنظمة. تصبح الحمولة القديمة غير الكائنية
`{ message }`. ترفض وعود طلب Fast وTTS بأخطاء عامة تحتفظ بالرسالة فقط بعد
استدعاءاتها المنظمة. لا تثبت المهلة النهائية: أوقف الإرسال، واحتفظ بالنتائج
المؤكدة، وسجل الإنهاء غير المكتمل، وافصل.
استخدم `retryable` كمدخل في سياسة إعادة محاولة محدودة، لا كإذن لإعادة محاولة
بلا حد. لا تعد رفعًا نتيجته ملتبسة بلا سياسة تطبيق لمنع التكرار.
## مرجع الأحداث المولد
يتوقف هذا الدليل عمدًا عند دورة الحياة والتأطير. تحتوي صفحات AsyncAPI المولدة
كل حقل وخاصية مطلوبة ومثال وقيد مخطط.
---
# نظرة عامة على الوصفات
Locale: ar
Source: https://docs.voice.humain.com/ar/recipes
تبدأ الوصفات بعد الإعداد وتنتهي بأثر قابل للاستخدام أو حالة نهائية. اختر حسب
ما يملكه تطبيقك كإدخال، لا حسب وسيلة النقل التي يبدو اسمها مألوفًا.
## قبل أن تبدأ
- استخدم SDK JavaScript أو Python بالإصدار `0.18.0`، وأكمل
[البدء السريع](/ar/quickstart) إذا لم تنفذ طلبًا مختبرًا.
- جهز `API_URL` و`API_KEY` الحاليين؛ ويستخدم Socket.IO المسار `/socket.io`
افتراضيًا. احتفظ بالمفتاح في بيئة خادم موثوقة.
- استخدم صوتًا أو نصًا ممثلاً، وحدد مكان حفظ الأثر المكتمل قبل تشغيل الوصفة.
يُعرض كل برنامج JavaScript وPython من الملف نفسه الذي تصرفه CI أو تفحص أنواعه
مقابل SDK `0.18.0`.
## اختر حسب الإدخال
## موضع النسخ السريع
النسخ السريع مسار SDK منفصل لـ**وحدة صوت مكتملة يهم كمونها**، مثل دور واحد
لوكيل أو محادثة. يرسل الوحدة المشفرة كاملة ثم يستلم أحداث النتائج. وهو ليس
بث ميكروفون مباشرًا، ولا توجه هذه الوثائق الاجتماعات أو البودكاست أو الأرشيفات
أو الوسائط الطويلة الأخرى إليه؛ استخدم وصفة Batch لها.
ابدأ من [دليل SDK](/ar/sdk) عندما يطابق النسخ السريع الإدخال.
## الخطوات التالية
تثبت الوصفة المكتملة أثرها المعلن ومسار التنظيف. قبل الإطلاق، كررها بمدخلات
ممثلة واختبر المهل، والحالات الطرفية، والانقطاع، وإعادة المحاولة، وضغط السعة،
وقوائم الأصوات الفارغة، ومعالجة الأسرار.
---
# النسخ الفوري
Locale: ar
Source: https://docs.voice.humain.com/ar/recipes/realtime-transcription
تبني هذه الوصفة جلسة نسخ مباشر واحدة بشكل مناسب للإنتاج. تبدأ بينما لا يزال
الصوت يصل، وتفصل حالة واجهة الاستخدام المؤقتة عن النص المثبت، وتكتب الترجمات
من الكلمات النهائية، وتغلق كل مورد عند حد محدد.
## متى تستخدم هذه الوصفة
اختر حسب حالة الصوت:
| حالة الصوت | استخدم | إدخال نموذجي |
|---|---|---|
| ما زال يصل | `RealtimeClient` (هذه الوصفة) | ميكروفون أو مكالمة أو مصدر مباشر آخر |
| مكتمل ومحدود وحساس لزمن الاستجابة | `FastTranscriptionClient` | دور محادثة واحد مكتمل لوكيل ذكاء اصطناعي |
| مكتمل وطويل | `BatchTranscribeClient` | اجتماع أو مقابلة أو بودكاست أو تسجيل أرشيفي |
يستقبل النسخ السريع وحدة صوتية مكتملة. ويمتلك Batch التسجيلات الطويلة المكتملة.
لا يحل أي منهما محل Realtime ASR عندما يجب أن يرسل المنتج الصوت قبل انتهاء
الكلام.
## قبل أن تبدأ
تحتاج إلى:
- JavaScript `@humain-voice/sdk@0.18.0` أو Python
`humain-voice==0.18.0` في وقت تشغيل موثوق على الخادم.
- القيم المخصصة `API_URL` و`API_KEY`. يستخدم تطبيقا `RealtimeClient`
المنشوران المسار `/socket.io` افتراضيًا.
- مصدر يستطيع توفير صوت PCM16 little-endian خام بتردد 16 kHz وأحادي القناة.
- مهلة للجلسة على مستوى التطبيق، ومكان يفصل الحالة المؤقتة والمثبتة وحالة
الخطأ.
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
أبقِ مفتاح API خارج شيفرة المتصفح وتطبيق الجوال. راجع
[المصادقة](/ar/authentication) لمسار بيانات الاعتماد في مؤسستك.
## 1. حضّر إدخال PCM خامًا
عقد صوت Realtime ASR محدد:
| الخاصية | القيمة المطلوبة |
|---|---|
| الترميز | PCM16 little-endian بإشارة |
| معدل العينات | 16,000 Hz |
| القنوات | أحادية |
| وتيرة المثال المختبر | 3,200 بايت كل 100 ms |
لاختبار قابل للتكرار، حوّل تسجيلًا إلى الصيغة الخام نفسها التي يجب أن ينتجها
مسار الميكروفون أو المكالمة:
```bash
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ar 16000 -ac 1 speech.pcm
```
أرسل البايتات الخام، لا ترويسة WAV أو حاوية مضغوطة. حجم 3,200 بايت والوتيرة
100 ms هما اختيار التأطير في المثال المختبر؛ أما صيغة الإدخال فهي عقد الخدمة.
## 2. شغّل المسار الناجح المختبر
تقرأ البرامج `speech.pcm`، وترسله بوتيرة منتج مباشر، وتصنف كل استجابة، وتجمع
كلمات الأحداث النهائية بترتيب الوصول، وتنتظر الحالة النهائية حتى خمس ثوان،
وتعرض `speech.vtt` باستخدام `Subtitles`، وتنظف العميل.
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
type ErrorResponse,
Language,
RealtimeClient,
Subtitles,
type WordSegment,
} from '@humain-voice/sdk';
const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'speech.pcm';
const outputPath = process.argv[3] ?? 'speech.vtt';
const client = new RealtimeClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
const finalizedWords: WordSegment[] = [];
let serverError: ErrorResponse | undefined;
let protocolFinalObserved = false;
try {
const stream = await client.startStream(Language.ArEn, {
onResponse: (response) => {
const kind = response.is_final
? 'final'
: response.is_speech_final
? 'speech-final'
: 'partial';
console.info(`${kind}:`, response.transcription);
if (response.is_final) protocolFinalObserved = true;
if (response.is_final || response.is_speech_final) {
// The current public Realtime contract does not guarantee increasing
// seq values, so collect final words in arrival order instead of
// asking RealtimeSubtitles to deduplicate by id:seq.
finalizedWords.push(...response.words);
}
},
// The released SDK can invoke a stream handler more than once for one
// routed error, so keep this callback idempotent.
onError: (error) => {
serverError = error;
},
});
const pcm = await readFile(inputPath);
for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
await pause(100);
}
// close() sends the last frame and waits for protocol is_final, a routed
// error, or this timeout. It resolves rather than throwing on timeout.
await stream.close(5);
if (serverError) {
throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
}
if (!protocolFinalObserved) {
throw new Error('Realtime stream ended before protocol is_final');
}
await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
CHUNK_BYTES = 3_200 # 100 ms of PCM16LE, 16 kHz, mono audio.
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "speech.vtt")
finalized_words: list[stt.WordSegment] = []
server_error: stt.ErrorResponse | None = None
protocol_final_observed = False
def handle_response(response: stt.RtTranscribeResponse) -> None:
nonlocal protocol_final_observed
if response.is_final:
kind = "final"
elif response.is_speech_final:
kind = "speech-final"
else:
kind = "partial"
print(f"{kind}:", response.transcription)
if response.is_final:
protocol_final_observed = True
if response.is_final or response.is_speech_final:
# The current public Realtime contract does not guarantee increasing
# seq values, so collect final words in arrival order instead of
# asking RealtimeSubtitles to deduplicate by id:seq.
finalized_words.extend(response.words)
def handle_error(error: stt.ErrorResponse | None) -> None:
# The released SDK can invoke a stream handler more than once for one
# routed error, so keep this callback idempotent.
nonlocal server_error
server_error = error
client = stt.RealtimeClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
stream = await client.start_stream(
language=stt.Language.ArEn,
on_response=handle_response,
on_error=handle_error,
)
pcm = input_path.read_bytes()
for offset in range(0, len(pcm), CHUNK_BYTES):
await stream.send(pcm[offset : offset + CHUNK_BYTES])
await asyncio.sleep(0.1)
# close() sends the last frame and waits for protocol is_final, a routed
# error, or this timeout. It returns rather than raising on timeout.
await stream.close(timeout_seconds=5.0)
if server_error is not None:
raise RuntimeError(server_error.message or server_error.code or "Realtime stream failed")
if not protocol_final_observed:
raise RuntimeError("Realtime stream ended before protocol is_final")
output_path.write_text(
stt.Subtitles.from_words(finalized_words).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
للتشغيل الناجح هذه النتائج الملحوظة:
1. تُطبع كل استجابة باسم `partial` أو`final` أو`speech-final` حسب راياتها.
2. لا يبقى خطأ خادم مسجل عند انتهاء التدفق.
3. يحتوي `speech.vtt` إشارات مبنية من توقيت الكلمات النهائية فقط.
4. يفصل عميل JavaScript داخل `finally`؛ ويغلق سياق Python غير المتزامن موارد
Socket.IO وHTTP الداخلية.
يجعل ملف PCM المحفوظ الاختبار قابلًا للتكرار. في الإنتاج، استبدل قراءة الملف
والمؤقت بمصدر الميكروفون أو المكالمة، مع إبقاء حدود الحالة والإنهاء والتنظيف
نفسها.
## 3. وفّق النص المؤقت والنهائي
النص الفوري حالة متغيرة، وليس سلسلة إلحاق واحدة. وجّه الاستجابات حسب `id` للبث،
وعيّن رقم وصول محليًا في التطبيق، وطبق جدول الانتقال التالي. أبقِ `seq` القادمة
من الخادم لبيانات التشخيص فقط لأن ترتيبها وتفرّدها ليسا جزءًا من العقد العام
الحالي.
| الإشارة | الحالة | إجراء واجهة الاستخدام والتخزين |
|---|---|---|
| `is_final=false`, `is_speech_final=false` | مؤقتة | استبدل العرض المؤقت الحالي لذلك التدفق؛ ولا تلحقه بالنص المثبت. |
| `is_final=true` مع أي قيمة لـ`is_speech_final` | نتيجة نهائية | ثبّت ذلك الحدث مرة بترتيب الوصول المرصود، ثم احذف القيمة المؤقتة التي تحل النتيجة محلها. |
| `is_final=false` و`is_speech_final=true` | نتيجة نهاية كلام | ثبّت كلمات ذلك الحدث بترتيب الوصول، وامسح النص المؤقت المستبدل، وسجل حد الكلام. |
| `onError` / `on_error` موجّه | تدفق فاشل | سجل الخطأ المنظم مرة، وأوقف تغذية الصوت، وابدأ التنظيف. |
اجعل استدعاء الخطأ قابلًا للتكرار بأمان. قد يستدعي SDK `0.18.0` معالج خطأ
التدفق أكثر من مرة لخطأ موجّه واحد.
لا تعرض استجابة مؤقتة متأخرة فوق نص مثبت. احتفظ بآخر نسخة مثبتة بصورة مستقلة
عن السطر المؤقت القابل للتغيير كي لا يمحو انقطاع الاتصال النتائج المستقرة.
## 4. أنشئ الترجمات من الكلمات النهائية
في استدعاء الاستجابة، تجاهل الكلمات ما دام علما النهاية `false`. ألحق كلمات
الأحداث النهائية أو أحداث نهاية الكلام بمصفوفة يملكها التطبيق حسب ترتيب الوصول
المرصود. بعد الإنهاء، مرر المصفوفة إلى `Subtitles.fromWords()` /
`Subtitles.from_words()` واعرض WebVTT.
يعرض SDK `0.18.0` أيضًا `RealtimeSubtitles`، الذي يتجاهل الأحداث المؤقتة ويزيل
تكرار الأحداث النهائية حسب `id:seq`. لا تستخدمه لجمع عدة أحداث نهائية مع العقد
السلكي الحالي، لأن قيم `seq` المتميزة غير مضمونة. تستخدم الأمثلة مسار التجميع
الذي يملكه التطبيق، ولا تكتب ملف الترجمات إلا بعد إغلاق التدفق وفحص الأخطاء
المسجلة.
## 5. أنهِ ضمن مهلة ونظف الموارد
عندما لا يبقى لدى المنتج صوت، استدعِ `close(5)` في JavaScript أو
`close(timeout_seconds=5.0)` في Python. في الإصدار `0.18.0`، يقوم الإغلاق بما
يلي:
1. يرسل إطار نهاية التدفق؛
2. ينتظر `is_final` على مستوى البروتوكول أو خطأً موجهًا أو انتهاء المهلة الممررة؛ و
3. ينجح عند انتهاء الانتظار بدل رفع خطأ مهلة.
الانتظار الافتراضي للنتيجة النهائية في SDK ثانية واحدة؛ تمرر الأمثلة خمس ثوان
عمدًا. تحد هذه المهلة انتظار الإغلاق فقط. احتفظ بمهلة تطبيق مستقلة للاتصال
وإنتاج الصوت والإرسال والجلسة كاملة.
لا يثبت نجاح الإغلاق وصول `is_final`. تمثل `is_speech_final` حد كلام ولا تنهي
انتظار الإغلاق. افحص حالة النهاية على مستوى البروتوكول والخطأ التي سجلتها
الاستدعاءات. إذا وجب التخلي عن التدفق، تزيل `stop()` / `stop_sync()` سياقه من
دون الانتظار النهائي.
نفذ دائمًا تنظيف العميل بعد إنهاء التدفق. قد يزيل الخطأ الموجه سياق التدفق قبل
تشغيل الإغلاق، لكن يجب أن تستدعي JavaScript الدالة `disconnect()` داخل
`finally`، ويجب أن تخرج Python من سياق العميل رغم ذلك.
## 6. تعافَ عبر حد تدفق جديد فقط
لا يحدد العقد العام استئنافًا شفافًا للجلسة أو حالة الخادم الباقية بعد انقطاع
الاتصال. عند خطأ موجّه أو انقطاع:
1. أوقف تغذية التدفق القديم واحتفظ بالنتائج النهائية المثبتة فقط.
2. تجاهل النص المؤقت غير المحسوم ونظف العميل القديم.
3. إذا سمحت مهلة التطبيق وسياسة الإعادة، فأعد الاتصال بتراجع محدود مع عشوائية
وأنشئ تدفقًا جديدًا بمعرّف جديد.
4. أبقِ نتائج التدفق الجديد منفصلة حتى يدمج التطبيق الخطين الزمنيين المثبتين
صراحة.
لا تفترض أن إعادة إرسال المقاطع السابقة آمنة؛ لا يوفر العقد موضع استئناف أو
إقرارًا لكل مقطع. قد يلزم الاحتفاظ بالصوت الملتقط حول الانقطاع ومعالجته على
حدة. راجع [دليل دورة حياة Realtime](/ar/api-guides/realtime) لحد التعافي
الكامل.
## الخطوات التالية
---
# توليد ملف WAV قابل للتشغيل
Locale: ar
Source: https://docs.voice.humain.com/ar/recipes/text-to-speech-to-file
تحول هذه الوصفة إدخالًا نصيًا يحتوي بعد إزالة الفراغات على حرف Unicode أو رقم
واحد على الأقل إلى ملف كامل لمشغل الوسائط. تكتشف صوتًا أثناء التشغيل، وتتوقف
بأمان عندما لا يعود أي صوت، وتنتظر الصوت
النهائي، وتكتب بيانات PCM الوصفية الصحيحة، وتغلق العميل في كل المسارات.
## متى تستخدم هذه الوصفة
استخدم المسار المخزن عندما يحتاج التطبيق إلى ملف WAV كامل قبل نشر النتيجة أو
تخزينها أو تشغيلها. إذا وجب بدء التشغيل أو المعالجة قبل انتهاء التوليف، فاستخدم
دالة البث الموضحة أدناه وأبقِ حدود المقطع النهائي والحاوية والمهلة والخطأ
والتنظيف نفسها.
تغطي هذه الوصفة TTS عبر Socket.IO باستخدام حزمتَي JavaScript وPython
المنشورتين. ولا تحدد عقد الخرج لنقل مختلف.
## قبل أن تبدأ
| المتطلب | عقد `0.18.0` |
|---|---|
| SDK | `@humain-voice/sdk@0.18.0` أو`humain-voice==0.18.0` في وقت تشغيل موثوق على الخادم |
| الاتصال | القيم المخصصة `API_URL` و`API_KEY`؛ ويستخدم SDK `/socket.io` افتراضيًا |
| النص | يحتوي بعد إزالة الفراغات على حرف Unicode أو رقم واحد على الأقل؛ ولا يقبل الفراغات فقط أو علامات الترقيم فقط |
| إدخال الصوت | واحد بالضبط من `voice_id` أو مجموعة `voice_references` غير فارغة |
| الخرج | وجهة قابلة للكتابة لملف WAV النهائي |
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
يكتشف المسار المختبر `voice_id`؛ ولا يفترض توفر صوت محدد أو أي صوت. أبقِ مفتاح
API في وقت التشغيل الموثوق؛ ويستخدم SDK المسار `/socket.io` افتراضيًا.
إذا استخدم التطبيق `voice_references` بدلًا من ذلك، فأرسل مرجعًا واحدًا يكون
صوته RIFF/WAVE بترميز base64 القياسي ويحتوي بيانات PCM16 أحادية غير فارغة.
## 1. اكتشف صوتًا
استدعِ `listVoices()` / `list_voices()` قبل التوليف عندما لا يكون التطبيق قد
استلم مرجع صوت مدعومًا.
| وقت التشغيل | القيمة الافتراضية المنشورة | هذه الوصفة |
|---|---|---|
| JavaScript | القيمة الافتراضية لـ`listVoices()` خمس ثوان | تمرر `timeoutSeconds: 5` صراحة |
| Python | لا مهلة لـ`list_voices()` ما لم تمرر | تمرر `timeout_seconds=5.0` |
تحتوي النتيجة سبع هويات متعددة اللغات بالشكل `{ id, label, profile }` عند
توفر كل النسخ المهيأة. تعامل مع القائمة كبيانات وقت تشغيل:
1. إذا كانت القائمة فارغة، فأوقف مسار `voice_id` هذا قبل فهرستها.
2. إذا فشل الطلب، فاحتفظ بحالة خطئه المنظمة ونظف الموارد.
3. إذا عاد صوت، فمرر `id` الدقيق؛ ولا تشتق معرّفًا من `label`.
يتيح تمرير معرّف هوية للمنصة اختيار نسختها الفعلية من النص. في هويات
العربية/الإنجليزية الحالية، يختار أي حرف من محارف الكتابة العربية النسخة
العربية؛ وإلا تُختار الإنجليزية. تبقى معرّفات النسخ الفعلية داخلية وتُرفض.
القائمة الفارغة نتيجة تشغيلية وليست وعدًا حول توفر الأصوات مستقبلًا. لا تخترع
معرّف صوت احتياطيًا.
## 2. شغّل المسار الناجح المختبر
تطلب البرامج الأصوات، وترفض القائمة الفارغة، وتختار `TtsModel.Nebula`، وتولد
النص `Hello from HUMAIN Voice`، وتشتق معدل عينات النموذج، وتكتب `speech.wav`،
وتغلق العميل.
JavaScript / TypeScript
Python
```ts
import { writeFile } from 'node:fs/promises';
import {
TTSClient,
TtsModel,
getSampleRate,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
function pcm16ToWav(pcm: Uint8Array, sampleRate: number): Buffer {
const header = Buffer.alloc(44);
header.write('RIFF', 0);
header.writeUInt32LE(36 + pcm.byteLength, 4);
header.write('WAVE', 8);
header.write('fmt ', 12);
header.writeUInt32LE(16, 16);
header.writeUInt16LE(1, 20); // Linear PCM.
header.writeUInt16LE(1, 22); // Mono.
header.writeUInt32LE(sampleRate, 24);
header.writeUInt32LE(sampleRate * 2, 28);
header.writeUInt16LE(2, 32);
header.writeUInt16LE(16, 34);
header.write('data', 36);
header.writeUInt32LE(pcm.byteLength, 40);
return Buffer.concat([
header,
Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength),
]);
}
async function main(): Promise {
const outputPath = process.argv[2] ?? 'speech.wav';
const client = new TTSClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
const voices = await client.listVoices({ timeoutSeconds: 5 });
const voice = voices.find((candidate) => candidate.profile) ?? voices[0];
if (!voice) throw new Error('No TTS voices are available');
if (voice.profile) {
console.log(
'profile:',
voice.label,
voice.profile.speaker.dialect,
voice.profile.languages,
);
}
const model = TtsModel.Nebula;
const pcm = await client.synthesize('Hello from HUMAIN Voice', {
voice_id: voice.id,
model,
// This is an inactivity timeout applied while awaiting each audio chunk.
timeoutSeconds: 30,
onError: (error) => console.error('server error:', error.code, error.message),
});
await writeFile(outputPath, pcm16ToWav(pcm, getSampleRate(model)));
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
import wave
from pathlib import Path
from humain_voice import stt, tts
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
def write_pcm16_wav(path: Path, pcm: bytes, sample_rate: int) -> None:
with wave.open(str(path), "wb") as wav_file:
wav_file.setnchannels(1)
wav_file.setsampwidth(2)
wav_file.setframerate(sample_rate)
wav_file.writeframes(pcm)
def handle_error(error: stt.ErrorResponse | None) -> None:
if error is not None:
print("server error:", error.code, error.message)
async def main() -> None:
output_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.wav")
async with tts.TTSClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
) as client:
voices = await client.list_voices(timeout_seconds=5.0)
if not voices:
raise RuntimeError("No TTS voices are available")
voice = next((item for item in voices if item.get("profile")), voices[0])
if profile := voice.get("profile"):
print(
"profile:",
voice["label"],
profile["speaker"]["dialect"],
profile["languages"],
)
model = tts.TtsModel.Nebula
pcm = await client.synthesize(
"Hello from HUMAIN Voice",
voice_id=voice["id"],
model=model,
# This is an inactivity timeout applied while awaiting each chunk.
timeout_seconds=30.0,
on_error=handle_error,
)
write_pcm16_wav(output_path, pcm, tts.get_sample_rate(model))
if __name__ == "__main__":
asyncio.run(main())
```
للتشغيل الناجح هذه النتائج الملحوظة:
1. يعيد اكتشاف الأصوات عنصرًا واحدًا على الأقل لهذا الطلب.
2. يستقبل التوليف المخزن مقطع الصوت النهائي من دون خطأ خادم مسجل أو انتهاء
مهلة الخمول.
3. يبدأ `speech.wav` بترويسة RIFF/WAVE صالحة تتبعها كل بايتات PCM المعادة،
ويمكن لمشغل يدعم WAV فتحه.
4. يغلق عميل JavaScript داخل `finally`؛ وتخرج Python من سياق العميل غير
المتزامن قبل كتابة الملف.
إذا لم يعد اكتشاف الأصوات أي عنصر، تفشل البرامج بوضوح ولا تنشئ ملفًا صامتًا
مضللًا.
## 3. غلّف PCM الخام في WAV
قيمة SDK المعادة بيانات صوت وليست ملف وسائط جاهزًا:
| الطبقة | القيمة المستخدمة في الأمثلة |
|---|---|
| صوت SDK | PCM16 little-endian خام بإشارة، بتردد 24 kHz، وأحادي القناة |
| عرض العينة | 16 بت، أو بايتان |
| ترويسة WAV | ترويسة RIFF/WAVE من 44 بايت تحمل صيغة PCM وعدد القنوات ومعدل العينات ومعدل البايتات ومحاذاة الكتل وطول البيانات |
| جسم WAV | كل بايتات PCM المعادة بعد وصول التوليف إلى مقطعه النهائي |
يحصل البرنامجان على معدل العينات عبر `getSampleRate(model)` /
`get_sample_rate(model)` بدل معاملة ترويسة الحاوية كجزء من استجابة SDK.
يقبل مساعد JavaScript نوع `Uint8Array` المنشور مباشرة، ويحافظ على
`byteOffset` و`byteLength` عند إنشاء `Buffer` في Node.js. تستخدم Python وحدة
`wave` القياسية لكتابة البيانات الوصفية نفسها.
ينطبق عقد PCM بتردد 24 kHz على TTS عبر Socket.IO وعملاء SDK هؤلاء. اقرأ عقد
العملية الحالي قبل تغليف البايتات المعادة من نقل آخر.
## 4. اختر التوليف المخزن أو المتدفق
| الوضع | API | النتيجة والمسؤولية |
|---|---|---|
| مخزن | `synthesize()` | يعيد `Uint8Array` واحدًا في JavaScript أو`bytes` في Python بعد أن يجمع SDK الصوت حتى المقطع النهائي. بسيط للملفات المحدودة، لكنه يحتفظ بنتيجة PCM كاملة في الذاكرة. |
| متدفق | `synthesizeStream()` / `synthesize_stream()` | يولد استجابات تحمل `id` و`audio` و`is_last`؛ عالج الصوت مبكرًا، وتتبع مجموع البايتات، وأنهِ حاوية صالحة فقط بعد الاستجابة النهائية. |
في الوضعين، يكون SDK قد أزال ترويسة إطار TTS عبر Socket.IO ذات 17 بايت. اكتب
بايتات `audio` لكل استجابة، لا الحمولة المؤطرة الأصلية. حد الشبكة أو المكرر
العشوائي ليس اكتمالًا؛ يحدد `is_last=true` استجابة الصوت النهائية.
يمكن للتوليف المخزن استقبال المقاطع أيضًا عبر `onAudio` / `on_audio`، لكن
الاستدعاء المخزن نفسه لا يكتمل إلا بعد جمع الصوت النهائي. إذا انتهى التدفق من
دون مقطع نهائي، فلا تنشر الملف الجزئي على أنه ملف كامل.
## 5. حد الخمول واحتفظ بحالة الخطأ
| وقت التشغيل | مهلة قائمة الأصوات | مهلة التوليف |
|---|---|---|
| JavaScript | افتراضيًا خمس ثوان | القيمة الافتراضية لـ`timeoutSeconds` هي 30 ثانية من الخمول |
| Python | لا قيمة افتراضية | لا قيمة افتراضية؛ مرر `timeout_seconds` دائمًا |
تستخدم الأمثلة صراحة خمس ثوان لاكتشاف الأصوات و30 ثانية للتوليف. قيمة التوليف
مهلة خمول أثناء انتظار مقطع الصوت التالي، وليست مهلة عامة للمسار. أضف مهلة
تطبيق مستقلة للاتصال والاكتشاف والتوليف وكتابة الملف والتنظيف.
ويفرض الخادم بصورة مستقلة مهلة كلية غير قابلة لإعادة الضبط قدرها 25 ثانية
ومراقب خمول قدره 60 ثانية. إذا سبقت المهلة الكلية الصوت النهائي، يصدر
`TTS_DEADLINE_EXCEEDED` القابل لإعادة المحاولة ويظل الصوت المستلم جزئيًا.
يعرض TTS سطحي خطأ مختلفين:
| السطح | المعلومات المحتفظ بها |
|---|---|
| استدعاء `onError` / `on_error` | كائن `ErrorResponse` مسوّى؛ قد تحتفظ الحمولات المنظمة بـ`id` و`code` و`retryable` و`timestamp` و`retry_after_seconds` و`data` و`reason` و`retry_scope` و`message`. تصبح الحمولة القديمة غير الكائنية رسالة. |
| التوليف المرفوض | `Error` عام في JavaScript أو`RuntimeError` في Python يحمل الرسالة فقط |
سجل حقول الاستدعاء المنظمة قبل التنظيف. لا تستنتج قابلية إعادة المحاولة من
تحليل رسالة الرفض العامة، ولا تدّع أن الإعادة آمنة عندما لا يوفر الاستدعاء
حالة كافية.
## 6. نظف الموارد وانشر ذريًا
أغلق العميل حتى عندما تكون قائمة الأصوات فارغة أو يفشل التوليف أو لا يصل
المقطع النهائي أو تفشل كتابة الملف. يستدعي مثال JavaScript
`client.close()` داخل `finally`؛ ويستخدم مثال Python عبارة `async with` لتحرير
Socket.IO وموارد HTTP الداخلية.
يغلق التنظيف اتصال العميل، فيلغي طلبات التوليف النشطة التي يملكها ذلك الاتصال
ويمنع أحداث الصوت والخطأ اللاحقة. ولا يغلق اتصالات الاستدلال المشتركة مع طلبات
أخرى.
في مسار ملفات الإنتاج، اكتب إلى وجهة مؤقتة ولا تكشف الملف إلا بعد الصوت
النهائي، وترويسة وجسم WAV مكتملين، وإغلاق ملف ناجح. يبقى التنظيف مطلوبًا إذا
فشل نشر الملف.
## الخطوات التالية
---
# نسخ تسجيل مع تسميات المتحدثين
Locale: ar
Source: https://docs.voice.humain.com/ar/recipes/transcribe-a-recording
تأخذ هذه الوصفة تسجيلًا مكتملًا واحدًا عبر سير عمل Batch يشبه الإنتاج: الإرسال،
والاستعلام حتى حالة نهائية، وتوفيق مقاطع المتحدثين، وكتابة التسميات، والتنظيف
في كل مسار.
## متى تستخدم هذه الوصفة
استخدم `BatchTranscribeClient` عندما يكون التسجيل كله موجودًا، خاصة للمواد
الطويلة أو الكبيرة مثل الاجتماعات والبودكاست والمكالمات والأرشيف. تحدّ إعداداتُ
Batch الافتراضية كل طلب بـ 512 ميبيبايت من بايتات الطلب و4 ساعات من الصوت
المفكوك؛ وللنسخ السريع حدود رفع منفصلة خاصة به. يُقبل الطلب المساوي تمامًا لحدٍّ
مُعَدّ ولا يُرفض إلا الطلب الذي يتجاوزه، لكن الحدود المنشورة قد تكون أدنى من هذه
القيم الافتراضية، لذا اختبر مواد تمثل استخدامك. لا يحدد API الدفعي مدة احتفاظ
بالنتيجة، لذا اجلب النتائج بسرعة ولا تصمم اعتمادًا على نافذة احتفاظ غير موثقة.
| حالة الصوت | اختر | السبب |
|---|---|---|
| تسجيل طويل ومكتمل | النسخ الدفعي | ارفع مرة واحدة واستعلم عن دورة حياة العمل |
| وحدة مكتملة وقصيرة وحساسة لزمن الوصول، مثل دور في محادثة وكيل | النسخ السريع | أرسل الحمولة المكتملة عبر Socket.IO لزمن وصول أقل |
| ما زال الصوت يصل | النسخ الفوري | أرسل مقاطع PCM وتعامل مع النتائج المؤقتة والنهائية |
النسخ السريع ليس مسار المواد الطويلة. استخدم Batch لسير عمل الاجتماع أو
البودكاست أو الأرشيف هذا.
## المتطلبات المسبقة
- تثبيت `@humain-voice/sdk@0.18.0` أو `humain-voice==0.18.0`.
- `API_KEY` الذي تحصل عليه عبر مسار الوصول في مؤسستك و`API_URL` المعروض
للبيئة. لا يستخدم Batch `API_PATH`؛ ويستخدم عملاء Socket.IO المسار
`/socket.io` افتراضيًا.
- ملف صوت مكتمل ومدعوم. تستخدم البرامج المختبرة `meeting.wav` افتراضيًا
وتكتب `meeting.vtt`.
- بيئة JavaScript على الخادم أو Python 3.10 أو أحدث. يستخدم مثال الاستعلام
المباشر في Python حزمة `httpx` أيضًا.
- مجلد خرج قابل للكتابة ومهلة تطبيق تناسب التسجيل وبيئة العامل.
تختار البرامج المختبرة `Language.ArEn` مع
`BatchTranscriptionModel.BayanArEn`. غيّر اللغة والنموذج معًا إذا احتاج
تسجيلك تركيبة أخرى مدعومة.
## 1. شغّل مسار SDK المختبر
اختر برنامجًا واحفظه باسم الملف المعروض. يفعّل البرنامجان التمييز، ويستعلمان
كل ثانيتين مع حد لحلقة الاستعلام قدره 300 ثانية، ويطبعان النص المعاد، ويكتبان
WebVTT نهائية، ويغلقان العميل أثناء التنظيف. قد يمدد الإرسال أو طلب قيد التنفيذ
المدة الفعلية.
JavaScript / TypeScript
Python
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
BatchDiarization,
BatchTranscribeClient,
BatchTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.wav';
const outputPath = process.argv[3] ?? 'meeting.vtt';
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
api_version: process.env.API_VERSION ?? 'v1',
});
try {
const result = await client.transcribe(
await readFile(inputPath),
Language.ArEn,
{
asr: BatchTranscriptionModel.BayanArEn,
diarization: BatchDiarization.On,
saveResult: true,
pollInterval: 2,
timeout: 300,
onProgress: ({ status }) => console.info('status:', status),
},
);
console.info(result.results?.transcript ?? '');
await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.batchtranscription import BatchDiarization
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.vtt")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
api_version=os.environ.get("API_VERSION", "v1"),
) as client:
result = await client.transcribe(
input_path,
lang=stt.Language.ArEn,
asr=stt.BatchTranscriptionModel.BayanArEn,
diarization=BatchDiarization.On,
save_result=True,
poll_interval=2.0,
timeout_seconds=300.0,
on_progress=lambda response: print("status:", response.status.value),
)
print(result.results.transcript if result.results else "")
output_path.write_text(
stt.Subtitles.from_response(result).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
شغّل البرنامج الذي حفظته:
- JavaScript / TypeScript في بيئة التحقق Node.js 24 للوثائق:
`node batch-transcription.ts meeting.wav meeting.vtt`
- Python: `python batch_transcription.py meeting.wav meeting.vtt`
## 2. تحقق من الآثار المتوقعة
في العمل الناجح:
| الأثر | النتيجة المتوقعة |
|---|---|
| خرج الطرفية | تحديث واحد أو أكثر يبدأ بـ`status:`، ثم النص المعاد |
| نتيجة Batch | الحالة النهائية `done`، مع إزاحات نص مطبعة عند التعرف على كلام |
| `meeting.vtt` | ملف WebVTT نهائي مولد بواسطة `Subtitles.fromResponse(result).toVtt()` |
| بيانات التمييز | مقاطع المتحدثين المعادة مع شكل النتيجة القديم الذي يستخدمه SDK الصادر |
قد ينتج الصوت الذي لا يحتوي كلامًا متعرفًا عليه نصًا فارغًا. تعامل مع إنشاء
ملف التسميات ووصول العمل إلى `done` كنجاح معالجة؛ وتحقق من فائدة المحتوى
بشكل منفصل.
ينجح مساعد SDK عند `done`، ويرفع خطأ عند `failed`، ويصل إلى مهلته المضبوطة
إذا بقيت المهمة `queued` أو`processing` أو`cleared`. لا يعرض `cleared` فورًا.
استخدم الاستعلام المباشر عندما يجب أن يميز التطبيق هذه الحالة بمجرد ظهورها.
## 3. قيّد الاستعلام المباشر عبر API
بعد إرسال `multipart/form-data` إلى `POST /v1/transcribe/{lang}`، استعلم من
عملية نتيجة V2 الموصى بها: `GET /v1/transcribe/{job_id}`. تحتاج الحلقة إلى
مهلة لكل طلب ومهلة إجمالية معًا.
JavaScript / TypeScript
Python
```ts
// `jobId` is the value returned by the submission request in step 2.
const jobId = process.env.JOB_ID!;
const deadline = Date.now() + 5 * 60_000;
let job;
while (Date.now() < deadline) {
const response = await fetch(`${process.env.API_URL}/v1/transcribe/${jobId}?save_result=true`, {
headers: {
"x-api-key": process.env.API_KEY!,
Origin: process.env.API_URL!,
},
signal: AbortSignal.timeout(10_000),
});
if (!response.ok) throw new Error(`poll failed: HTTP ${response.status}`);
({ data: job } = await response.json());
if (job.status === "done") break;
if (job.status === "failed") {
throw new Error("transcription failed");
}
if (job.status === "cleared") {
throw new Error("transcription result is unavailable (cleared)");
}
await new Promise((resolve) => setTimeout(resolve, 2_000));
}
if (!job || job.status !== "done") throw new Error("poll deadline exceeded");
```
```python
import os
import time
import httpx
API_URL = os.environ["API_URL"]
API_KEY = os.environ["API_KEY"]
# `job_id` is the value returned by the submission request in step 2.
job_id = os.environ["JOB_ID"]
deadline = time.monotonic() + 5 * 60
job = None
with httpx.Client(timeout=10.0) as http:
while time.monotonic() < deadline:
response = http.get(
f"{API_URL}/v1/transcribe/{job_id}",
headers={"x-api-key": API_KEY, "Origin": API_URL},
params={"save_result": "true"},
)
response.raise_for_status()
job = response.json()["data"]
if job["status"] == "done":
break
if job["status"] == "failed":
raise RuntimeError("transcription failed")
if job["status"] == "cleared":
raise RuntimeError("transcription result is unavailable (cleared)")
time.sleep(2)
if job is None or job["status"] != "done":
raise TimeoutError("poll deadline exceeded")
```
`queued` و`processing` حالتان غير نهائيتين؛ و`done` و`failed` و`cleared`
حالات نهائية. استخدم النتائج عند `done` فقط، واعرض إخفاق العمل عند `failed`،
واعتبر النتيجة غير متاحة عند `cleared`.
تضبط هذه الحلقات `save_result=true` قبل جلب الحالة النهائية كي يمكن جلب
استجابة `done` أو `failed` مجددًا بعد فقدها. قد تمسح القيمة الافتراضية `false`
الحقول المخزنة بعد بناء تلك الاستجابة. لا يضمن الخيار مدة احتفاظ.
فاصل الثانيتين، ومهلة الطلب البالغة عشر ثوانٍ، والمهلة الإجمالية البالغة خمس
دقائق أعلاه اختيارات للتطبيق وليست ضمانات خدمة. تعامل مع `429` باستخدام
السعة المبلغ عنها وتراجع محدود. لا تعد قراءة النتيجة إلا عندما يحفظها
`save_result=true`؛ ولا تكرر رفعًا انتهت مهلته بلا تمييز لأنه ربما أنشأ عملًا
بالفعل.
## 4. وفّق الكلمات والمتحدثين
تفصل استجابة V2 بين `final_word_segments` و`diarization_segments`. تسند
سياسة التطبيق الصريحة التالية الكلمة إلى المقطع الذي يحتوي منتصفها. وعند
غياب تطابق، تحتفظ بـ`UNKNOWN_SPEAKER`.
JavaScript / TypeScript
Python
```ts
function speakerFor(word, segments) {
const midpoint = (word.start_time + word.end_time) / 2;
return segments.find(
(segment) =>
segment.start_time <= midpoint && midpoint < segment.end_time,
)?.speaker ?? "UNKNOWN_SPEAKER";
}
const attributed = job.final_word_segments.map((word) => ({
...word,
speaker: speakerFor(word, job.diarization_segments ?? []),
}));
```
```python
def speaker_for(word, segments):
midpoint = (word["start_time"] + word["end_time"]) / 2
segment = next(
(
item
for item in segments
if item["start_time"] <= midpoint < item["end_time"]
),
None,
)
return (segment or {}).get("speaker") or "UNKNOWN_SPEAKER"
attributed = [
{
**word,
"speaker": speaker_for(word, job.get("diarization_segments") or []),
}
for word in job["final_word_segments"]
]
```
مطابقة منتصف النطاق الزمني قاعدة تطبيق وليست ضمان هوية. وثّق سياسة مختلفة
لأقرب مقطع أو التداخل إذا اخترتها. تميز تسميات المتحدثين الأدوار؛ ولا تعرّف
أشخاصًا حقيقيين.
يمكن لمسار V1 القديم إعادة `speaker` مباشرة على إزاحات الكلمات عند تفعيل
المحاذاة القسرية. افصل نوعي استجابة V1 وV2 بدل خلط أسماء حقولهما.
## 5. أنشئ التسميات التوضيحية
يكتب مسار SDK المختبر مسبقًا `meeting.vtt` من إزاحات الكلمات المطبعة. استخدم
`toSrt()` بدل `toVtt()` عندما يتطلب المستهلك SubRip. في عميل V2 مباشر، طبّع
أولًا توقيت الكلمات المعاد إلى شكل دخل عارض التسميات؛ ولا تمرر غلاف V2 إلى
مساعد يتوقع `TranscriptionResponse` القديمة في SDK الصادر.
نص التسميات والخط الزمني للمتحدثين أثران منفصلان. WebVTT وSRT صيغتا تسميات
توضيحية؛ أما RTTM فهي صيغة تمييز.
## 6. تعامل مع الفشل والتنظيف
| الحالة | إجراء الإنتاج |
|---|---|
| مفتاح مفقود أو غير صالح | توقف وصحح إعداد الخادم؛ ولا تعرض المفتاح في شيفرة العميل أو السجلات |
| `429` | اقرأ معلومات السعة عند وجودها وطبّق تراجعًا محدودًا مع jitter |
| `failed` | توقف عن الاستعلام واعرض خطأ العمل |
| `cleared` | توقف عن الاستعلام وأبلغ أن النتيجة غير متاحة؛ ولا تستنتج مدة احتفاظ |
| المهلة الإجمالية | أوقف العامل وسجل معرّف المهمة حتى يمكن التحقق من النتيجة |
| مهلة رفع بلا `jobId` | تعامل مع النتيجة كملتبسة؛ ولا ترفع المادة نفسها مجددًا بلا تمييز |
يغلق مثال JavaScript المتحقق منه عميله داخل `finally`؛ ويستخدم مثال Python
مدير سياق غير متزامن. يستخدم مستعلم Python المباشر مدير سياق متزامن لعميل
HTTP. حافظ على حدود التنظيف هذه عند إضافة التخزين أو الطوابير أو نشر
التسميات.
## الخطوات التالية
إذا كان مسار SDK مناسبًا، فأعد تشغيله على تسجيلات تمثل استخدامك واختبر المهل
وإعادة المحاولة والتنظيف. وإذا كان العامل يملك الإرسال والاستعلام بشكل منفصل،
فتابع إلى عقد Batch REST قبل تنفيذ جانب الرفع.
---
# نظرة SDK العامة
Locale: ar
Source: https://docs.voice.humain.com/ar/sdk
استخدم هذه الصفحة لاختيار الحمل ووقت التشغيل، ثم انتقل إلى دليل JavaScript أو
Python للاطلاع على المنشئات والخيارات وحقول الاستجابة وثوابت الأحداث والبرامج
المختبرة بدقة. يصدر Go SDK من العقد نفسه، ويشير الرابط أدناه إلى توثيق مصدره.
**عقد الإصدار:** تستهدف هذه الوثائق بالضبط `@humain-voice/sdk@0.18.0` و
`humain-voice==0.18.0` ووحدة Go الموسومة `golang/v0.18.0`. تغلف حزم SDK خدمات
Batch REST وSocket.IO، ولا تغلف عمليات Realtime HTTP. يضيف هذا الإصدار ثوابت
عامة وتصنيف أخطاء TTS لرفض سياسة المحتوى وتعذر الإشراف عليه.
## اختر حسب المهمة
ابدأ من شكل الصوت، لا من اسم العميل:
| المدخل والهدف | اختر | السبب |
|---|---|---|
| تسجيل مكتمل، وخصوصًا اجتماع أو مقابلة أو بودكاست أطول | النسخ الدفعي (`BatchTranscribeClient`) | ارفع الملف مرة، واستلم معرّف مهمة، واستعلم حتى حالة طرفية ضمن مهلة التطبيق. |
| وحدة صوتية مكتملة وحساسة لزمن الاستجابة، مثل دور محادثة واحد لوكيل برمجي | النسخ السريع (`FastTranscriptionClient`) | أرسل الوحدة المكتملة عبر Socket.IO واستقبل تحديثات نسخ جزئية ونهائية. |
| صوت ما زال يصل من ميكروفون أو مكالمة أو مصدر مباشر | Realtime ASR (`RealtimeClient`) | أرسل أجزاء PCM16 ووفّق النص المؤقت والنهائي ونهائي الكلام. |
| خط زمني مباشر للمتحدثين | التمييز الفوري (`RealtimeDiarizationClient`) | أرسل الصوت أثناء استهلاك تحديثات مقاطع المتحدثين الموفقة. |
| نص ينبغي تحويله إلى كلام | TTS عبر Socket.IO (`TTSClient`) | اكتشف صوتًا، ثم استقبل أجزاء الصوت المولّد بصيغة PCM16. |
النسخ السريع مخصص لوحدة مكتملة ومحدودة وحساسة لزمن الاستجابة. ليس هو المسار
لتسجيل طويل أو بودكاست؛ استخدم Batch لهذه الأحمال.
يشكّل `Subtitles` توقيت الكلمات المكتملة بعد اختيار عميل النسخ. يُصدر
`RealtimeSubtitles` أيضًا، لكن إزالة التكرار فيه حسب `id:seq` تتطلب أن يوفر
السلك قيم تسلسل متميزة؛ راجع قسم النهائية أدناه. كلاهما مساعد نتائج وليس عميل
نقل.
إذا احتجت إلى بث HTTP مباشر بدل عميل SDK، فاستخدم
[دليل Realtime HTTP](/ar/api-guides/realtime-http).
## اختر وقت تشغيل على الخادم
| دليل اللغة | الإصدار المحدد | عقد التشغيل |
|---|---|---|
| [JavaScript وTypeScript](/ar/sdk/javascript) | `@humain-voice/sdk@0.18.0` | ES2021 مع `fetch` و`FormData` و`Blob`؛ يسمي README الخاص بـ SDK بيئتي Node.js وBun على الخادم |
| [Python](/ar/sdk/python) | `humain-voice==0.18.0` | Python 3.10 أو أحدث |
| [Go](https://gitlab.humain.com/humain/data-and-ai-modeling/library/sautech-sdk/-/tree/golang/v0.18.0/golang) | `golang/v0.18.0` | وحدة Go 1.25 مع توثيق الحزم وأمثلتها في المصدر الموسوم |
### تعامل مع نتائج سياسة محتوى TTS
| رمز السلك | تصدير JavaScript وPython | تصدير Go في `errcodes` | الإعادة |
|---|---|---|---|
| `TTS_INPUT_NOT_ALLOWED` | `TTS_INPUT_NOT_ALLOWED` | `TTSInputNotAllowed` | لا؛ غيّر النص |
| `TTS_MODERATION_UNAVAILABLE` | `TTS_MODERATION_UNAVAILABLE` | `TTSModerationUnavailable` | نعم، مع تراجع محدود |
تصنف مساعدات JavaScript `isTtsCode()` و`isTtsOwned()`، ومساعدات Python
`is_tts_code()` و`is_tts_owned()`، ومساعدات Go `IsTTSCode()` و`IsTTSOwned()`
الرمزين على أنهما مملوكان لـTTS. احتفظ بالاستدعاء المنظم قبل أن يرفض استدعاء
التوليف بخطئه العام الذي يحتفظ بالرسالة فقط.
لا تنشر حزمة JavaScript حدًا أدنى لإصدار Node.js أو Bun. تعمل أمثلة الوثائق
باستخدام Node.js 24 وBun 1.3.14؛ تصف هذه الإصدارات بيئة تحقق الوثائق وليست وعد
دعم من SDK.
استخدم `humain_voice` في شيفرة Python الجديدة. تبقى مساحة `sautech` التاريخية
في `0.18.0` استيراد توافق وتصدر تحذير إهمال.
## اضبط الإصدار 0.18.0
اضبط القيم الصادرة لبيئتك في وقت تشغيل موثوق على الخادم:
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
```
يستخدم Batch القيم `API_URL` و`API_KEY` و`API_VERSION`. ويتطلب عملاء
Socket.IO القيمتين `API_URL` و`API_KEY` فقط ويستخدمون `/socket.io` افتراضيًا.
اضبط `API_PATH` فقط عندما يستخدم النشر مسارًا مخصصًا؛ وتتطلب نقطة النهاية
القديمة `sautech.humain.com` المسار `/realtime/socket.io`.
راجع [المصادقة](/ar/authentication) لمسار بيانات الاعتماد في مؤسستك والتعامل
مع المفتاح على الخادم.
## امتلك دورة الحياة والمهل
### أغلق التدفق وعميله
عادة يحرر إغلاق التدفق الناجح جلسة Socket.IO عندما لا تبقى سياقات للطلبات.
قد يزيل الخطأ الموجه سياق الطلب قبل تشغيل `close()`، لذلك يجب أن ينظف النطاق
المالك العميل رغم ذلك.
استخدم `finally` لعملاء JavaScript. وفي Python، استخدم مدير السياق غير
المتزامن أو المتزامن المدعوم حيث يوضحه دليل اللغة. أوقف إرسال الصوت بعد الخطأ
وافصل الاتصال حتى إذا عاد إغلاق التدفق نفسه بالفعل.
### اضبط مهلة لكل عملية
- **Batch:** يستعلم `transcribe` كل ثانيتين مع حد افتراضي لحلقة الاستعلام قدره
300 ثانية. قد يمدد الإرسال أو طلب قيد التنفيذ المدة الفعلية؛ ولا يتوقف
المساعد المنشور عند `cleared` بل يصل إلى الحد.
- **النسخ السريع:** لا تملك JavaScript خيار مهلة للطلب في SDK. القيمة
الافتراضية في Python هي 60 ثانية. احتفظ بمهلة تطبيق في وقتي التشغيل.
- **Realtime ASR:** ينتظر إغلاق التدفق النتيجة النهائية حتى ثانية واحدة
افتراضيًا. ينهي انتهاء المهلة الانتظار، لكنه لا يثبت وصول نتيجة نهائية.
- **التمييز الفوري:** ينتظر الإغلاق حتى خمس ثوان ويعيد أفضل خط زمني موفق معروف
إذا انتهى انتظار النتيجة النهائية.
- **قائمة الأصوات وTTS:** القيم الافتراضية في JavaScript هي خمس ثوان لقائمة
الأصوات و30 ثانية من الخمول للتوليف. لا تطبق Python مهلة ما لم تمرر واحدة.
هذه ضوابط للعميل؛ ويفرض الخادم أيضًا مهلة كلية غير قابلة لإعادة الضبط قدرها
25 ثانية ومراقب خمول قدره 60 ثانية. تعامل مع قائمة أصوات فارغة وأغلق العميل
في وقتي التشغيل.
## فسّر النتائج حسب المرحلة
### ميّز النتائج المؤقتة والطرفية
- **Batch:** اعتبر `done` و`failed` و`cleared` حالات طرفية في مستعلم يملكه
التطبيق. ينجح مساعد `transcribe` المنشور عند `done`، ويرفع خطأً عند `failed`،
ولا ينتهي مبكرًا عند `cleared`.
- **النسخ السريع:** استخدم `is_final` لاستبدال النص الجزئي بالنتيجة النهائية
للوحدة الصوتية المكتملة.
- **Realtime ASR:** تكون النتيجة مؤقتة ما دام `is_final` و`is_speech_final`
كلاهما `false`. استبدل نص واجهة الاستخدام المؤقت بدل إلحاقه كنسخة ثانية.
- **التمييز الفوري:** تمثل `segments` الخط الزمني الموفق؛ لا يمثل
`newlyFinalized` / `newly_finalized` سوى الزيادة النهائية الجديدة.
- **TTS:** اجمع الصوت أو ابثه حتى `is_last`؛ البايتات المعادة PCM16 خام وليست
حاوية WAV.
### أنشئ الترجمات من التوقيت النهائي فقط
يقرأ `Subtitles.fromResponse()` في JavaScript و`result.subtitles()` في Python
إزاحات الكلمات الموحدة ويولدان SRT أو WebVTT. يتجاهل `RealtimeSubtitles`
الاستجابات الجزئية ويزيل تكرار الاستجابات النهائية حسب `id:seq`. لا يضمن عقد
Realtime السلكي الحالي قيم `seq` متميزة، لذلك اجمع كلمات الأحداث النهائية
بترتيب الوصول واعرضها باستخدام `Subtitles` عندما يمكن أن ينتج التدفق عدة أحداث
نهائية. يبقى النص المؤقت على الشاشة مسؤولية التطبيق.
مقاطع المتحدثين مخرج مختلف. صدّرها عبر `toRttm()` في JavaScript أو
`to_rttm()` في Python، أو وفقها مع كلمات ASR النهائية عند إنشاء ترجمات منسوبة
إلى المتحدثين.
### احتفظ بالأخطاء المنظمة قبل إعادة المحاولة
تعرض استثناءات Batch HTTP حقول الحالة والرمز وقابلية إعادة المحاولة والسعة
وتأخير الإعادة مع استخدام `statusCode` / `retryAfter` في JavaScript و
`status_code` / `retry_after` في Python عند توفرها.
يمكن لاستدعاءات أخطاء النسخ السريع وTTS الاحتفاظ بكائن `ErrorResponse` منظم.
تستخدم وعود JavaScript أو استدعاءات Python المرفوضة أخطاء عامة تحمل الرسالة
فقط في مسار الفشل الموجه، لذلك سجل حقول الاستدعاء المنظمة قبل التنظيف.
`maxRetries` / `max_retries` مهمل ومتجاهل في `0.18.0`. أضف سياسة إعادة محاولة
محدودة في التطبيق، ولا تكرر رفعًا غامض النتيجة بلا تمييز. راجع
[الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits).
## الخطوات التالية
اختر دليلًا واتبع برنامجه المختبر للعميل المحدد. صفحات اللغة هي مرجع العمليات
العامة الدقيقة والتنظيف الخاص باللغة؛ أما هذه النظرة فهي خريطة القرار.
} href="/ar/sdk/javascript" title="JavaScript وTypeScript" description="ثبّت الإصدار المحدد، وافحص سطح العملاء العام، وشغّل أمثلة المهام المصرّفة." />
} href="/ar/sdk/python" title="Python" description="اختر العمليات غير المتزامنة أو المتزامنة المدعومة، وافحص الاستيرادات الدقيقة، وشغّل أمثلة المهام المفحوصة نوعيًا." />
---
# JavaScript وTypeScript
Locale: ar
Source: https://docs.voice.humain.com/ar/sdk/javascript
يستهدف هذا الدليل وسم الإصدار الدقيق `javascript/v0.18.0`. تُصرّف برامجه
الستة مقابل ذلك الوسم وتُعرض من ملفات المصدر المختبرة نفسها.
## التثبيت والإعداد
ثبّت الإصدار الموثق:
```bash
npm install @humain-voice/sdk@0.18.0
```
تستهدف الحزمة ES2021 وتستخدم `fetch` و`FormData` و`Blob`. لا تعلن حدًا أدنى
لإصدار Node.js أو Bun. تُفحص أمثلة الوثائق باستخدام Node.js 24 وBun 1.3.14؛
وهما بيئتا تحقق وليستا وعد دعم من SDK.
اضبط القيم الصادرة لبيئتك:
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
```
يتطلب عملاء Socket.IO الحقلين `api_url` و`api_key` فقط؛ ويستخدم الإصدار
`0.18.0` المسار `/socket.io` افتراضيًا. مرّر `api_path` فقط عند استخدام نشر
بمسار مخصص، أو مع نقطة النهاية القديمة `sautech.humain.com` التي تتطلب
`/realtime/socket.io`. احتفظ بـ`API_KEY` في إعدادات الخادم.
ينتج المثال الناجح نتيجة تطبيق، لا مجرد اتصال: يكتب Batch صيغة WebVTT، ويكتب
Fast صيغة SRT، ويكتب Realtime صيغة WebVTT النهائية، ويعيد التمييز المباشر خطًا
زمنيًا موفقًا، ويكتب TTS ملف WAV قابلًا للتشغيل.
## اختر العميل
| المهمة | العميل | اختره عندما |
|---|---|---|
| نسخ تسجيل مكتمل | `BatchTranscribeClient` | يكون الملف الكامل موجودًا، خاصة اجتماعًا أو بودكاست أو مكالمة أو مادة أرشيفية أطول |
| نسخ وحدة صوت مكتملة وقصيرة بزمن وصول أقل | `FastTranscriptionClient` | تكون الحمولة المكتملة متاحة بالفعل، مثل دور واحد في محادثة وكيل |
| نسخ الصوت أثناء وصوله | `RealtimeClient` | ما زال ميكروفون أو مكالمة أو مصدر مباشر ينتج الصوت |
| بناء خط زمني مباشر للمتحدثين | `RealtimeDiarizationClient` | تحتاج إلى مقاطع متحدثين متغيرة ونهائية |
| توليد الكلام | `TTSClient` | تحتاج إلى خرج PCM متدفق من نص |
النسخ السريع ليس مسار المحتوى الطويل. استخدم Batch للاجتماعات والبودكاست
والمواد الأرشيفية؛ واستخدم Fast لوحدات صوت قصيرة ومكتملة وحساسة لزمن الوصول.
## انسخ تسجيلًا مكتملًا
يفعّل برنامج Batch المختبر تمييز المتحدثين، ويستعلم مع حد لحلقة الاستعلام قدره
300 ثانية، ويطبع النص، ويكتب WebVTT نهائية. قد يمدد الإرسال أو طلب قيد التنفيذ
المدة الفعلية.
| العقد | سلوك الإصدار `0.18.0` |
|---|---|
| المُنشئ | `new BatchTranscribeClient({ api_url, api_key, api_version="v1", maxRetries? })` |
| الصوت المقبول | `ArrayBuffer` أو `Uint8Array` أو `Blob` أو `File` |
| العمليات | `submit()` و`getResult()` و`transcribe()` و`close()` |
| الخيارات | خيارات `submit`: `diarization` و`asr` و`itn` و`redact`؛ و`getResult`: `saveResult`؛ و`transcribe`: تلك الخيارات مع `pollInterval` (2 s) و`timeout` (300 s) و`onProgress` و`saveResult` |
| النتيجة والنهائية | يعيد `submit()` النوع `JobResponse`؛ ينجح المساعد عند `done`، ويرفع خطأ عند `failed`، وتنتهي مهلته إذا بقيت المهمة `queued` أو `processing` أو `cleared` |
| التنظيف والأخطاء | `close()` عام ولا ينفذ عملًا حاليًا. `maxRetries` مهمل ومتجاهل؛ تستخدم إخفاقات Batch هرم الأنواع الموضح في قسم إعادة المحاولة. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
BatchDiarization,
BatchTranscribeClient,
BatchTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.wav';
const outputPath = process.argv[3] ?? 'meeting.vtt';
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
api_version: process.env.API_VERSION ?? 'v1',
});
try {
const result = await client.transcribe(
await readFile(inputPath),
Language.ArEn,
{
asr: BatchTranscriptionModel.BayanArEn,
diarization: BatchDiarization.On,
saveResult: true,
pollInterval: 2,
timeout: 300,
onProgress: ({ status }) => console.info('status:', status),
},
);
console.info(result.results?.transcript ?? '');
await writeFile(outputPath, Subtitles.fromResponse(result).toVtt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
استخدم `submit(audio, language, options)` و
`getResult(jobId, language, options)` عندما يملك عامل أو طابور الاستعلام. يجب
أن يتوقف المستعلم المخصص صراحة عند `done` و`failed` و`cleared`.
قد تمسح القيمة الافتراضية `saveResult=false` نتيجة `done` أو `failed` بعد بناء
الاستجابة. اضبط `saveResult: true` قبل الاستعلام عندما يجب أن يتحمل تسليم
النتيجة النهائية فقد استجابة؛ ولا يحدد API مدة احتفاظ.
يقرأ `Subtitles.fromResponse(result)` القيم من `result.results.offsets`؛ استخدم
`toSrt()` أو `toVtt()`. تعرض استجابات Batch أيضًا `diarization_segments`
عندما يعيدها مسار النتيجة القديم.
## انسخ وحدة صوت مكتملة وقصيرة
يرسل النسخ السريع حمولة الصوت **المكتملة** مرة واحدة عبر Socket.IO. وهو محسّن
لوحدات قصيرة وحساسة لزمن الوصول مثل دور في محادثة وكيل؛ وليس عميل الاجتماعات
الطويلة أو البودكاست.
| العقد | سلوك الإصدار `0.18.0` |
|---|---|
| المُنشئ | `new FastTranscriptionClient({ api_url, api_key, api_path?, onConnect?, onFileUpload?, onError? })` |
| الصوت المقبول | `ArrayBuffer` أو `Uint8Array` أو `Blob` تحتوي حمولة الصوت المكتملة |
| العمليات | `connect()` و`transcribe()` و`close()` |
| الاستدعاء | `transcribe(audio, language, model, { onResponse?, onFileUpload?, onError?, diarizationModel?, itnModel?, redactModel? })` |
| النتيجة والنهائية | يستقبل `onFileUpload` إقرار الرفع؛ ويمكن أن يستقبل `onResponse` نتائج جزئية قبل `FtTranscribeResponse` النهائية. يعيد الوعد الاستجابة النهائية أو `undefined`. |
| المهلة والتنظيف والأخطاء | لا يوجد خيار مهلة في SDK. طبّق مهلة تطبيق وأغلق صراحة. يستدعي خطأ الطلب الموجه `onError` ثم يرفض بـ`Error` عام يحتفظ بالرسالة فقط. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
FastTranscriptionClient,
FastTranscriptionModel,
Language,
Subtitles,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function withDeadline(operation: Promise, milliseconds: number): Promise {
let timer: ReturnType | undefined;
try {
return await Promise.race([
operation,
new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error('Fast transcription deadline exceeded')), milliseconds);
}),
]);
} finally {
if (timer) clearTimeout(timer);
}
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'short-call.wav';
const outputPath = process.argv[3] ?? 'short-call.srt';
const client = new FastTranscriptionClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
await client.connect();
const result = await withDeadline(
client.transcribe(
await readFile(inputPath),
Language.Ar,
FastTranscriptionModel.BayanAr,
{
onFileUpload: (response) => console.info('uploaded:', response?.id),
onResponse: (response) => {
console.info(response.is_final ? 'final:' : 'partial:', response.transcription);
},
onError: (error) => console.error('server error:', error.code, error.message),
},
),
60_000,
);
if (!result) throw new Error('Fast transcription ended without a final result');
await writeFile(outputPath, Subtitles.fromResponse(result).toSrt(), 'utf8');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
يرفض المثال غياب النتيجة النهائية ولا يكتب SRT إلا بعد النهائية. لا تعد
الإرسال بلا تمييز بعد مهلة ملتبسة: لا ينشر API عقد idempotency-key. يعرض SDK
`0.18.0` القيم `diarizationModel` و`itnModel` و`redactModel` للتوافق مع
البروتوكول، لكن خدمة Fast العامة المتحقق منها لا تطبقها. احذفها، واستخدم Batch
عندما تحتاج إلى خيارات المعالجة هذه.
## انسخ الصوت أثناء وصوله
دخل Realtime هو PCM16 little-endian بتردد 16 kHz وأحادي القناة. يرسل البرنامج
المختبر مقاطع حجمها 3,200 بايت، أي 100 ms من الصوت، ويكتب WebVTT نهائية.
| العقد | سلوك الإصدار `0.18.0` |
|---|---|
| المُنشئ | `new RealtimeClient({ api_url, api_key, api_path? })`؛ ويعرض العميل أيضًا خصائص الاستدعاء |
| العمليات | `connect()` و`startStream()` و`disconnect()` |
| البدء | `startStream(language, { onConnect?, onDisconnect?, onResponse?, onError?, subtitles? })` |
| التدفق | `send(audio, isLast=false)` و`close(timeoutSeconds=1)` و`stop()` |
| النتيجة والنهائية | يحمل `RtTranscribeResponse` الحقول `seq` و`is_final` و`is_speech_final`؛ يحدد `is_speech_final` نهاية مقطع كلام، ولا ينهي التدفق إلا `is_final` على مستوى البروتوكول |
| التنظيف والأخطاء | يرسل `close()` النهاية وينتظر؛ ويزيل `stop()` التدفق بلا انتظار. قد يزيل خطأ موجه سياق التدفق، لذلك استدعِ دائمًا `disconnect()` على مستوى العميل داخل `finally`. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
type ErrorResponse,
Language,
RealtimeClient,
Subtitles,
type WordSegment,
} from '@humain-voice/sdk';
const CHUNK_BYTES = 3_200; // 100 ms of PCM16LE, 16 kHz, mono audio.
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'speech.pcm';
const outputPath = process.argv[3] ?? 'speech.vtt';
const client = new RealtimeClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
const finalizedWords: WordSegment[] = [];
let serverError: ErrorResponse | undefined;
let protocolFinalObserved = false;
try {
const stream = await client.startStream(Language.ArEn, {
onResponse: (response) => {
const kind = response.is_final
? 'final'
: response.is_speech_final
? 'speech-final'
: 'partial';
console.info(`${kind}:`, response.transcription);
if (response.is_final) protocolFinalObserved = true;
if (response.is_final || response.is_speech_final) {
// The current public Realtime contract does not guarantee increasing
// seq values, so collect final words in arrival order instead of
// asking RealtimeSubtitles to deduplicate by id:seq.
finalizedWords.push(...response.words);
}
},
// The released SDK can invoke a stream handler more than once for one
// routed error, so keep this callback idempotent.
onError: (error) => {
serverError = error;
},
});
const pcm = await readFile(inputPath);
for (let offset = 0; offset < pcm.length; offset += CHUNK_BYTES) {
await stream.send(pcm.subarray(offset, offset + CHUNK_BYTES));
await pause(100);
}
// close() sends the last frame and waits for protocol is_final, a routed
// error, or this timeout. It resolves rather than throwing on timeout.
await stream.close(5);
if (serverError) {
throw new Error(serverError.message ?? serverError.code ?? 'Realtime stream failed');
}
if (!protocolFinalObserved) {
throw new Error('Realtime stream ended before protocol is_final');
}
await writeFile(outputPath, Subtitles.fromWords(finalizedWords).toVtt(), 'utf8');
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
استبدل النص المؤقت بترتيب الوصول المرصود حتى تصل إحدى رايتي النهاية. يجمع
المثال كلمات الأحداث النهائية بنفسه ويعرضها باستخدام `Subtitles`؛ ولا يعتمد على
`seq` لأن ترتيبها وتفرّدها ليسا جزءًا من عقد السلك العام الحالي. يزيل
`RealtimeSubtitles` التكرار حسب `id:seq` وقد يدمج أحداثًا نهائية متميزة بموجب ذلك
العقد. ينتظر `stream.close(timeoutSeconds)` قيمة `is_final` على مستوى
البروتوكول أو خطأ موجهًا أو مهلته. ويعود بدل رفع خطأ عند انتهاء المهلة؛ ولا
تنهي `is_speech_final` ذلك الانتظار.
## ابنِ خطًا زمنيًا مباشرًا للمتحدثين
يجمع SDK زيادات المقاطع النهائية ويستبدل الذيل النشط ليعرض خطًا زمنيًا واحدًا
موفقًا في `update.segments`.
| العقد | سلوك الإصدار `0.18.0` |
|---|---|
| المُنشئ | `new RealtimeDiarizationClient({ api_url, api_key, api_path? })` |
| العمليات | `connect()` و`startStream()` و`disconnect()` |
| خيارات البدء | تكون `language` افتراضيًا `Language.Ar`؛ واستدعاءات الاتصال والتحديث والخطأ اختيارية |
| التدفق | يعرض `streamId` و`speakers` و`send()` و`close(5)` ومكررًا غير متزامن واحدًا |
| النتيجة والنهائية | يحتوي `DiarizationUpdate` على `segments` الموفقة و`newlyFinalized` و`activeSegments` و`isFinal` و`raw` |
| التنظيف والأخطاء | استهلك التحديثات أثناء إرسال الصوت ثم افصل. أخطاء المكرر هي `DiarizationStreamError`؛ ويعيد `close(5)` أفضل خط زمني معروف إذا انتهت مهلة الانتظار النهائي، لكنه لا ينهي مكررًا منتظرًا في مسار المهلة. |
```ts
import { readFile, writeFile } from 'node:fs/promises';
import {
DIARIZATION_RECOMMENDED_CHUNK_BYTES,
RealtimeDiarizationClient,
type SpeakerSegment,
toRttm,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function main(): Promise {
const inputPath = process.argv[2] ?? 'meeting.pcm';
const outputPath = process.argv[3] ?? 'meeting.rttm';
const client = new RealtimeDiarizationClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
let finalObserved = false;
const stream = await client.startStream({
onError: (error) => console.error('server error:', error.code, error.message),
onUpdate: (update) => {
finalObserved ||= update.isFinal;
for (const segment of update.newlyFinalized) {
console.info(segment.speaker, segment.start_time, segment.end_time);
}
},
});
const pcm = await readFile(inputPath);
if (pcm.length === 0 || pcm.length % 2 !== 0) {
throw new Error('Input must be nonempty PCM16 with an even byte length');
}
for (
let offset = 0;
offset < pcm.length;
offset += DIARIZATION_RECOMMENDED_CHUNK_BYTES
) {
await stream.send(
pcm.subarray(offset, offset + DIARIZATION_RECOMMENDED_CHUNK_BYTES),
);
await pause(480);
}
// close() returns the best-known reconciled timeline after five seconds,
// even when no isFinal update arrived. A callback avoids leaving an async
// iterator waiting forever on that timeout path.
const timeline: SpeakerSegment[] = await stream.close(5);
const destination = finalObserved ? outputPath : `${outputPath}.partial`;
await writeFile(destination, toRttm(timeline, 'meeting'), 'utf8');
if (!finalObserved) {
console.warn(`Final result not observed; wrote incomplete output to ${destination}`);
}
} finally {
await client.disconnect();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
قيمة `DIARIZATION_RECOMMENDED_CHUNK_BYTES` هي 15,360 بايت، أي 480 ms بصيغة
الصوت المطلوبة. قد يعلق المسار إذا لم تبدأ الاستهلاك إلا بعد انتهاء التغذية.
يستخدم المثال `onUpdate` كي لا تترك المهلة مكررًا منتظرًا، ويكتب ملف RTTM
بلاحقة `.partial` ما لم يرصد `isFinal`.
## ولّد الكلام واكتب WAV
تعيد `listVoices()` هويات متعددة اللغات بالشكل `{ id, label, profile }`. يحمل
`profile` بيانات `speaker` مشتركة وقائمة `languages` مفتوحة؛ مرر `id` الخاص
بالهوية نفسها في `voice_id`.
تعامل مع قائمة فارغة قبل التوليف. يعيد TTS عبر Socket.IO بايتات PCM16
little-endian خام بتردد 24 kHz وأحادية القناة، لا حاوية WAV.
في هويات العربية/الإنجليزية الحالية، يختار أي حرف من محارف الكتابة العربية
في `text` النسخة العربية؛ وإلا تُختار الإنجليزية. تبقى معرّفات النسخ الفعلية
داخلية وتُرفض.
| العقد | سلوك الإصدار `0.18.0` |
|---|---|
| المُنشئ | `new TTSClient({ api_url, api_key, api_path?, verbose?, onConnect?, onError? })`؛ يُقبل `verbose` لكن لا سلوك له |
| العمليات | `connect()` و`listVoices()` و`synthesize()` و`synthesizeStream()` و`close()` |
| المدخلات | نص يحتوي بعد إزالة الفراغات على حرف Unicode أو رقم واحد على الأقل، وواحد بالضبط من `voice_id` أو `voice_references` غير الفارغة؛ أرسل للمسار العام مرجعًا واحدًا `{ text, audio }` يكون `audio` فيه RIFF/WAVE بترميز base64 القياسي وبيانات PCM16 أحادية غير فارغة |
| القيم الافتراضية | مهلة قائمة الأصوات 5 s؛ و`model=TtsModel.Nebula`؛ و`timeoutSeconds=30` ثانية من الخمول |
| الخيارات الأخرى | `onAudio` في الاستدعاء المخزن فقط، و`onError`، و`request_id` |
| النتيجة والتنظيف والأخطاء | النوع `TtsAudioResponse` هو `{ id, is_last, audio: Uint8Array }`. أغلق صراحة. يتلقى `onError` بيانات منظمة ومطبعة، بينما يكون رفض التوليف `Error` عامًا يحتفظ بالرسالة فقط. |
```ts
import { writeFile } from 'node:fs/promises';
import {
TTSClient,
TtsModel,
getSampleRate,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_PATH' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
function pcm16ToWav(pcm: Uint8Array, sampleRate: number): Buffer {
const header = Buffer.alloc(44);
header.write('RIFF', 0);
header.writeUInt32LE(36 + pcm.byteLength, 4);
header.write('WAVE', 8);
header.write('fmt ', 12);
header.writeUInt32LE(16, 16);
header.writeUInt16LE(1, 20); // Linear PCM.
header.writeUInt16LE(1, 22); // Mono.
header.writeUInt32LE(sampleRate, 24);
header.writeUInt32LE(sampleRate * 2, 28);
header.writeUInt16LE(2, 32);
header.writeUInt16LE(16, 34);
header.write('data', 36);
header.writeUInt32LE(pcm.byteLength, 40);
return Buffer.concat([
header,
Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength),
]);
}
async function main(): Promise {
const outputPath = process.argv[2] ?? 'speech.wav';
const client = new TTSClient({
api_url: requiredEnv('API_URL'),
api_path: requiredEnv('API_PATH'),
api_key: requiredEnv('API_KEY'),
});
try {
const voices = await client.listVoices({ timeoutSeconds: 5 });
const voice = voices.find((candidate) => candidate.profile) ?? voices[0];
if (!voice) throw new Error('No TTS voices are available');
if (voice.profile) {
console.log(
'profile:',
voice.label,
voice.profile.speaker.dialect,
voice.profile.languages,
);
}
const model = TtsModel.Nebula;
const pcm = await client.synthesize('Hello from HUMAIN Voice', {
voice_id: voice.id,
model,
// This is an inactivity timeout applied while awaiting each audio chunk.
timeoutSeconds: 30,
onError: (error) => console.error('server error:', error.code, error.message),
});
await writeFile(outputPath, pcm16ToWav(pcm, getSampleRate(model)));
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
استخدم `synthesizeStream()` لمعالجة `response.audio` عند وصوله. يحتفظ الخطأ
المنظم بـ`code` و`retryable`؛ وتُطبع الحمولة القديمة غير الكائنية إلى
`{ message }`. يحافظ المثال على نطاق بايتات `Uint8Array` ويضيف ترويسة WAV
الصحيحة.
ويفرض الخادم بصورة مستقلة مهلة كلية غير قابلة لإعادة الضبط قدرها 25 ثانية
ومراقب خمول قدره 60 ثانية. إذا سبقت المهلة الكلية الإطار النهائي، يكون
`TTS_DEADLINE_EXCEEDED` قابلاً لإعادة المحاولة ويظل الصوت المستلم جزئيًا.
مساعدو TTS العامون هم `TtsModel.Nebula` و`DEFAULT_SAMPLE_RATE` و
`MODEL_SAMPLE_RATES` و`getSampleRate()` و`decodeTtsAudioFrame()`.
## أعد محاولة قراءة Batch محفوظة
ينفذ SDK `0.18.0` استدعاء HTTP واحدًا لكل عملية Batch. يعيد هذا المثال قراءة
نتيجة بتراجع أسي محدود ويمرر `saveResult: true` قبل جلب الحالة النهائية. من
دون هذا الخيار، قد تتبع الاستجابة النهائية المفقودة حالة `cleared`، لذلك ليست
القراءة الافتراضية idempotent في كل الحالات.
| الاستثناء | الحقول المنشورة |
|---|---|
| `BatchTranscribeError` | `statusCode` و`payload` و`code` و`retryable` و`jobId` و`detail` و`timestamp` و`capacity` و`rawBody` |
| `BatchTranscribeAuthError` | نوع فرعي لإخفاق المصادقة |
| `BatchTranscribeTimeoutError` | يضيف `elapsed` |
| `BatchTranscribeJobFailedError` | يضيف `error` و`errorCode` |
| `BatchTranscribeRateLimitError` | يضيف `retryAfter` |
```ts
import {
BatchTranscribeClient,
BatchTranscribeError,
BatchTranscribeRateLimitError,
Language,
type TranscriptionResponse,
} from '@humain-voice/sdk';
function requiredEnv(name: 'API_KEY' | 'API_URL'): string {
const value = process.env[name];
if (!value) throw new Error(`${name} is required`);
return value;
}
async function pause(milliseconds: number): Promise {
await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
async function getResultWithRetry(
client: BatchTranscribeClient,
jobId: string,
attempts = 5,
): Promise {
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
// saveResult prevents a terminal read from clearing the stored result
// before a retry. It does not establish a retention duration.
return await client.getResult(jobId, Language.ArEn, { saveResult: true });
} catch (error: unknown) {
if (!(error instanceof BatchTranscribeError)) throw error;
const rateLimited = error instanceof BatchTranscribeRateLimitError;
const retryable = rateLimited || error.retryable === true;
console.error({
statusCode: error.statusCode,
code: error.code,
capacity: error.capacity,
});
if (!retryable || attempt === attempts) throw error;
const serverDelayMs = rateLimited && error.retryAfter !== undefined
? error.retryAfter * 1_000
: 0;
const exponentialDelayMs = 500 * 2 ** (attempt - 1);
await pause(Math.max(serverDelayMs, exponentialDelayMs) + Math.random() * 250);
}
}
throw new Error('Retry loop exhausted');
}
async function main(): Promise {
const jobId = process.argv[2];
if (!jobId) throw new Error('Pass a batch job ID as the first argument');
const client = new BatchTranscribeClient({
api_url: requiredEnv('API_URL'),
api_key: requiredEnv('API_KEY'),
});
try {
const result = await getResultWithRetry(client, jobId);
console.info(result.status, result.results?.transcript ?? '');
} finally {
await client.close();
}
}
void main().catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
});
```
`maxRetries` مهمل ومتجاهل. لا تطبق هذه الحلقة بلا تمييز على إنشاء المهمة: بعد
مهلة، قد لا يعرف العميل هل أنشأ الرفع عملًا أم لا.
## مرجع الاستجابات والمساعدين في الإصدار
| النوع أو المساعد | الحقول أو السلوك المنشور |
|---|---|
| `JobResponse` | `jobId` و`status` |
| `TranscriptionResponse` | `status`؛ والحقول الاختيارية `results` و`APIVersion` و`version` و`metadata` و`diarization_segments` و`error` و`errorCode`. تحتوي النتائج `transcript` والإزاحات، وتحتوي البيانات الوصفية `sautechVersion` و`jobId` و`fileDuration`. |
| مساعدو Batch | `isComplete` و`isFailed` و`isPending` و`getJobId` و`getFileDuration`؛ ويصدر `BatchDiarization` و`BatchRedact` وثوابت الحالة والنموذج. |
| `FileUploadedResponse` / `FtTranscribeResponse` | الرفع: `id` و`message` اختياري. نتيجة Fast: `id` و`seq` و`transcription` و`words` و`is_final`. |
| `RtTranscribeResponse` | حقول Fast مع `is_speech_final`. |
| `DiarizationUpdate` | `id` و`segments` الموفقة و`newlyFinalized` و`activeSegments` و`isFinal` و`raw`. |
| `SpeakerContext` / `VoiceProfile` / `VoiceInfo` | `{ gender, dialect }`؛ و`{ speaker, languages }`؛ و`{ id, label, profile? }`. توفر الواجهة الحالية `profile` دائمًا. |
| `VoiceReference` / `TtsAudioResponse` | `{ text, audio }`؛ و`{ id, is_last, audio: Uint8Array }`. |
| `ErrorResponse` | الحقول الاختيارية `id` و`message` و`code` و`retryable` و`timestamp` و`retry_after_seconds` و`data` و`reason` و`retry_scope`؛ ويسوي `parseErrorResponse()` الحمولات القديمة غير الكائنية. |
قد يصل خطأ Socket غير القابل للتوجيه إلى الاستدعاء العام فقط. احتفظ بمهلة
للتطبيق ونظّف دائمًا. تستدعي أخطاء طلب Fast `onError` ثم ترفض بـ`Error` عام؛
ويشير Realtime إلى استدعائه وانتظاره النهائي؛ وترفع مكررات التمييز
`DiarizationStreamError`؛ وتحتفظ استدعاءات TTS بالبيانات المنظمة بينما تحتفظ
وعود التوليف المرفوضة بالرسالة فقط.
## صادرات الأحداث والأخطاء منخفضة المستوى
تصدر الحزمة العليا `generateUuid()` ومشفرات إطار Fast وRealtime وثوابت
الأعلام.
| ثوابت الأحداث | قيم السلك |
|---|---|
| `EVENT_FT_ERROR`, `EVENT_FT_TRANSCRIBE_FILE`, `EVENT_FT_TRANSCRIBE_FILE_UPLOAD_SUCCESS`, `EVENT_FT_TRANSCRIBE_RESULT` | `error`, `audio_file`, `audio_file_upload_success`, `transcription_result` |
| `EVENT_RT_AUDIO_STREAM`, `EVENT_RT_END_AUDIO_STREAM` | `audio_stream`, `end_audio_stream` |
| `EVENT_DIARIZATION_STREAM`, `EVENT_DIARIZATION_RESULT` | `diarization_stream`, `diarization_result` |
| `EVENT_TTS_REQUEST`, `EVENT_TTS_AUDIO`, `EVENT_TTS_ERROR` | `tts`, `tts_audio`, `error` |
| `EVENT_TTS_VOICE_LIST_REQUEST`, `EVENT_TTS_VOICE_LIST_RESULT` | `tts_voice_list`, `tts_voice_list_result` |
| مجموعة رموز الخطأ | الثوابت |
|---|---|
| المصادقة | `AUTH_UNAUTHORIZED`, `AUTH_KEY_INVALID`, `AUTH_FORBIDDEN` |
| التحقق | `VALIDATION_INVALID_LANGUAGE`, `VALIDATION_INVALID_FORMAT`, `VALIDATION_REQUIRED_FIELD`, `VALIDATION_FILE_CORRUPT`, `VALIDATION_INVALID_PARAM`, `VALIDATION_INVALID_UUID` |
| الحدود والفوترة | `RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`, `CONCURRENCY_LIMIT_EXCEEDED`, `CREDITS_EXHAUSTED`, `BILLING_AUTHORIZATION_UNAVAILABLE`, `PAYLOAD_TOO_LARGE`, `AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`, `CHARACTER_COUNT_EXCEEDED`, `VOICE_REFERENCE_COUNT_EXCEEDED` ورموز `SESSION_*` المصدّرة |
| ASR | `ASR_TRANSCRIPTION_FAILED`, `ASR_MODEL_NOT_FOUND`, `ASR_MODEL_UNAVAILABLE`, `ASR_STREAM_EXPIRED`, `ASR_UNSUPPORTED_CODEC`, `ASR_STREAM_NOT_FOUND` |
| TTS | `TTS_SYNTHESIS_FAILED`, `TTS_DEADLINE_EXCEEDED`, `TTS_MODEL_NOT_FOUND`, `TTS_VOICE_NOT_FOUND`, `TTS_VOICE_RESOLUTION_FAILED`, `TTS_VOICE_LIST_FAILED`, `TTS_INPUT_NOT_ALLOWED`, `TTS_MODERATION_UNAVAILABLE`, `TTS_MODEL_UNAVAILABLE`, `TTS_INVALID_INPUT` |
| المتحدث والتمييز | `SPEAKER_ID_FAILED`, `DIARIZATION_FAILED`, `DIARIZATION_MODEL_NOT_FOUND` |
| الخادم وBatch والتوافق | `SERVER_INTERNAL`, `SERVER_DEPENDENCY_FAILURE`, `METHOD_NOT_ALLOWED`, `TRANSCRIPTION_JOB_NOT_FOUND`, `RATE_LIMITED`, `VALIDATION_FAILED`, `INTERNAL_ERROR` |
يوجّه الإصدار `0.18.0` أخطاء حدود العمل والفوترة وسياسة محتوى TTS إلى سياق الطلب النشط، فيُرفض
الاستدعاء المعلّق بدل انتظار مهلته. اقرأ `data` لمعرفة الحد، واحترم
`retry_after_seconds` عند ضغط قابل لإعادة المحاولة، وافتح تدفقًا جديدًا عندما
يحمل `ASR_STREAM_EXPIRED` القيمة `retry_scope: "new_stream"`.
استخدم `isAsrCode()` و`isTtsCode()` و`isRequestScopedCode()` و
`isRealtimeOwned()` و`isTtsOwned()` و`isDiarizationCode()` و
`isDiarizationOwned()` لتوجيه أخطاء Socket المنظمة. لا تغني هذه المصنفات عن
مهلة سير العمل أو التنظيف عند وصول خطأ غير قابل للتوجيه.
## مرجع التسميات التوضيحية
| API | العقد |
|---|---|
| `Subtitles` | `SubtitleCue` و`SubtitleOptions` و`SubtitleRenderOptions` و`SubtitleError`؛ مُنشئ من cues؛ `cues`؛ `fromWords` و`fromCues` و`fromResponse`؛ `toSrt` و`toVtt` |
| `RealtimeSubtitles` | `words` و`cues` و`addResponse` و`subtitles` و`toSrt` و`toVtt`؛ يتجاهل النتائج المؤقتة ويلغي تكرار استجابات `id:seq` النهائية |
| المساعدون العلويون | `wordsToCues` و`cuesToSrt` و`cuesToVtt` و`subtitles` و`toSrt` و`toVtt` |
| قيم التشكيل الافتراضية | `maxDurationSeconds=6` و`maxGapSeconds=0.7` و`minDurationSeconds=0.5` و`maxCharsPerLine=42` و`maxLines=2` و`splitOnSpeakerChange=true` و`strict=false`؛ يبدأ `startIndex=1` في SRT |
يقبل دخل التسميات إزاحات Batch ذات camel-case وكلمات Realtime ذات snake-case.
استخدم الوضع الصارم عندما يجب أن يفشل التوقيت غير الصالح أو غير المرتب بدل
تسويته أو تخطيه.
## الخطوات التالية
---
# Python
Locale: ar
Source: https://docs.voice.humain.com/ar/sdk/python
يستهدف هذا الدليل بالضبط **`humain-voice==0.18.0`** على Python 3.10 أو أحدث.
تُحلل برامجه المعروضة وتُفحص أنواعها مقابل وسم الإصدار `python/v0.18.0`.
## ثبّت واضبط
ثبّت الحزمة المثبتة الإصدار في بيئة الخادم أو البيئة الافتراضية:
```bash
python -m pip install humain-voice==0.18.0
```
اضبط القيم الصادرة لبيئتك:
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
export API_VERSION="v1"
```
استورد الشيفرة الجديدة عبر `humain_voice`. مساحة `sautech` التاريخية استيراد
توافق مهمل في `0.18.0` وتصدر تحذيرًا.
يستخدم Batch القيم `API_URL` و`API_KEY` و`API_VERSION`. ويتطلب عملاء
Socket.IO الحقلين `api_url` و`api_key` فقط، ويكون `api_path` افتراضيًا
`/socket.io`. مرّر مسارًا فقط لتجاوز النشر؛ وتتطلب نقطة النهاية القديمة
`sautech.humain.com` المسار `/realtime/socket.io`.
يدعم كل عميل Python التنظيف غير المتزامن ومديري السياق غير المتزامن والمتزامن.
تغطية الدوال غير متناظرة: استخدم فقط الدوال المتزامنة المسماة لكل عميل أدناه.
لا توجد دالتا `connect_sync()` أو `disconnect_sync()` عامتان.
## المهمة الأولى: انسخ تسجيلًا مكتملًا
ابدأ بـ`BatchTranscribeClient` عندما يكون التسجيل الكامل موجودًا، وخصوصًا
لاجتماع طويل أو بودكاست أو مقابلة أو ملف أرشيف. احفظ هذا المصدر المختبر باسم
`batch_transcription.py` بجانب تسجيل الإدخال:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.batchtranscription import BatchDiarization
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.vtt")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
api_version=os.environ.get("API_VERSION", "v1"),
) as client:
result = await client.transcribe(
input_path,
lang=stt.Language.ArEn,
asr=stt.BatchTranscriptionModel.BayanArEn,
diarization=BatchDiarization.On,
save_result=True,
poll_interval=2.0,
timeout_seconds=300.0,
on_progress=lambda response: print("status:", response.status.value),
)
print(result.results.transcript if result.results else "")
output_path.write_text(
stt.Subtitles.from_response(result).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
شغله مع ملف إدخال ومسار خرج:
```bash
python batch_transcription.py meeting.wav meeting.vtt
```
يبلغ التشغيل الناجح عن تقدم المهمة، ويطبع النسخة النهائية، ويكتب إشارات WebVTT
النهائية في `meeting.vtt`.
### سطح Batch المنشور
| السطح | عقد `0.18.0` |
|---|---|
| المُنشئ | `BatchTranscribeClient(api_url, api_key, max_retries=0, api_version="v1")` |
| الدوال غير المتزامنة | `submit()`, `get_result()`, `transcribe()`, `close()` |
| الدوال المتزامنة | `submit_sync()`, `get_result_sync()`, `transcribe_sync()`, `close_sync()` |
| الخيارات والقيم الافتراضية | `submit`: `diarization`, `asr`, `itn`, `redact`؛ `get_result`: `save_result`؛ `transcribe`: هذه الخيارات مع `poll_interval=2` و`timeout_seconds=300` و`on_progress` و`save_result`. الخيار `max_retries` متجاهل. |
| الإدخال | يقبل `AudioInput` الدفعي القيم الشبيهة بالبايت، ومسار `Path` أو سلسلة، والقراء المخزنين، و`BytesIO`. |
ينجح `transcribe()` عند `done`، ويرفع خطأً عند `failed`، ويواصل الاستعلام عن
`queued` أو`processing` أو`cleared` حتى مهلته. إذا كان العامل يملك حلقة
الاستعلام، فتوقف صراحة عند الحالات الطرفية الثلاث: `done` و`failed` و`cleared`.
قد تمسح القيمة الافتراضية `save_result=False` نتيجة `done` أو `failed` بعد
بناء الاستجابة. مرر `save_result=True` قبل الاستعلام عندما يجب أن يتحمل تسليم
النتيجة النهائية فقد استجابة. لا ينشئ ذلك مدة احتفاظ بالنتيجة.
استخدم العميل كمدير سياق غير متزامن أو عادي. يغلق خروج السياق جلسة `aiohttp`
الداخلية. تفهرس أقسام المرجع أدناه أنواع نتائج Batch والترجمات.
## اختر مهمة أخرى
| المدخل والهدف | العميل | إشارة الاكتمال |
|---|---|---|
| تسجيل مكتمل أو اجتماع طويل أو بودكاست أو مقابلة أو وسائط أرشيف | `BatchTranscribeClient` | تصل المهمة إلى `done` أو`failed` أو`cleared` |
| وحدة صوتية مكتملة وحساسة لزمن الاستجابة، مثل دور محادثة واحد لوكيل ذكاء اصطناعي | `FastTranscriptionClient` | تحمل الاستجابة النهائية `is_final=True` |
| صوت ما زال يصل من ميكروفون أو مكالمة أو مصدر مباشر | `RealtimeClient` | تحمل استجابة البروتوكول `is_final=True` |
| تقسيم مباشر للمتحدثين | `RealtimeDiarizationClient` | يصل التحديث النهائي أو يعيد الإغلاق أفضل خط زمني معروف |
| تحويل النص إلى كلام مولّد | `TTSClient` | تحمل استجابة الصوت `is_last=True` |
النسخ السريع ليس مسار الاجتماعات الطويلة أو البودكاست أو وسائط الأرشيف. استخدم
Batch لهذه التسجيلات الأطول والمكتملة.
## مهمة سريعة: انسخ وحدة محادثة مكتملة
استخدم `FastTranscriptionClient` بعد اكتمال وحدة صوتية محدودة وحساسة لزمن
الاستجابة، مثل دور مستخدم واحد في محادثة مع وكيل ذكاء اصطناعي. يرسل الوحدة
كاملة عبر Socket.IO؛ ولا يقبل تدفق ميكروفون مفتوح النهاية.
### سطح Fast المنشور
| السطح | عقد `0.18.0` |
|---|---|
| المُنشئ | `FastTranscriptionClient(api_url, api_key, api_path=None, on_connect?, on_file_upload?, on_error?, verbose=False)`؛ ويبقى ترتيب ما قبل 0.17 `(api_url, api_path, api_key, ...)` مدعومًا مع تحذير إهمال |
| الدوال غير المتزامنة | `connect()`, `transcribe()`, `close()` |
| الدوال المتزامنة | `transcribe_sync()`, `close_sync()`؛ لا توجد `connect_sync()` |
| الخيارات والقيم الافتراضية | يقبل `transcribe(audio, language, model, …)` القيم `on_response` و`on_file_upload` و`on_error` و`timeout_seconds=60` و`diarization_model` و`itn_model` و`redact_model`. |
| الإدخال | `bytes` أو قارئ مخزن؛ يجب فتح المسار أو قراءته أولًا. |
يبلغ هذا البرنامج المختبر عن تقدم الرفع، ويميز النص الجزئي والنهائي، ويتطلب
نتيجة نهائية، ويكتب SRT:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
def handle_response(response: stt.FtTranscribeResponse) -> None:
kind = "final" if response.is_final else "partial"
print(f"{kind}:", response.transcription)
def handle_upload(response: stt.FileUploadedResponse) -> None:
print("uploaded:", response.id)
def handle_error(error: stt.ErrorResponse | None) -> None:
if error is not None:
print("server error:", error.code, error.message)
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "short-call.wav")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "short-call.srt")
async with stt.FastTranscriptionClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
) as client:
result = await client.transcribe(
input_path.read_bytes(),
stt.Language.Ar,
stt.FastTranscriptionModel.BayanAr,
on_response=handle_response,
on_file_upload=handle_upload,
on_error=handle_error,
timeout_seconds=60.0,
)
if result is None:
raise RuntimeError("Fast transcription ended without a final result")
output_path.write_text(
stt.Subtitles.from_response(result).to_srt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
يحدد `FileUploadedResponse` عملية الرفع. تتلقى الاستدعاءات الجزئية والنهائية
`FtTranscribeResponse`؛ وتحمل الاستجابة النهائية المعادة `is_final=True` ويمكنها
إنشاء الترجمات. المهلة الافتراضية في Python هي 60 ثانية.
يقبل SDK `0.18.0` القيم `diarization_model` و`itn_model` و`redact_model`
للتوافق مع البروتوكول، لكن خدمة Fast العامة المتحقق منها لا تطبقها. احذفها،
واستخدم Batch عندما تحتاج إلى خيارات المعالجة هذه.
لا تعد إرسال الوحدة الصوتية بلا تمييز بعد مهلة غامضة؛ لا يوجد عقد منشور لمفتاح
idempotency. استخدم مدير سياق العميل كي تغلق موارد Socket.IO وHTTP الداخلية في
كل المسارات.
## مهمة فورية: انسخ الصوت عند وصوله
استخدم `RealtimeClient` لصوت ميكروفون أو مكالمة أو صوت آخر ما زال يصل. يجب أن
يكون الإدخال PCM16 little-endian بتردد 16 kHz وأحادي القناة.
### سطح Realtime المنشور
| السطح | عقد `0.18.0` |
|---|---|
| المُنشئ | `RealtimeClient(api_url, api_key, api_path=None, verbose=False)` |
| الدوال غير المتزامنة | `connect()`, `start_stream()`, `disconnect()` |
| الدوال المتزامنة | `start_stream_sync()`؛ دوال التدفق `send_sync()` و`close_sync()` و`stop_sync()` عامة، لكن `connect_sync()` و`disconnect_sync()` ليستا كذلك |
| خيارات البدء | `language`, `on_connect`, `on_disconnect`, `on_response`, `on_error`, `subtitles` |
| التدفق | `send()` / `send_sync()`؛ يرسل `close(timeout_seconds=1)` / `close_sync()` النهاية وينتظر؛ يزيل `stop()` / `stop_sync()` التدفق من دون الانتظار النهائي. |
يرسل هذا البرنامج مقاطع حجمها 3,200 بايت، تمثل 100 ms من الصوت المطلوب، ويغلق
العميل عبر مدير السياق غير المتزامن:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
CHUNK_BYTES = 3_200 # 100 ms of PCM16LE, 16 kHz, mono audio.
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "speech.vtt")
finalized_words: list[stt.WordSegment] = []
server_error: stt.ErrorResponse | None = None
protocol_final_observed = False
def handle_response(response: stt.RtTranscribeResponse) -> None:
nonlocal protocol_final_observed
if response.is_final:
kind = "final"
elif response.is_speech_final:
kind = "speech-final"
else:
kind = "partial"
print(f"{kind}:", response.transcription)
if response.is_final:
protocol_final_observed = True
if response.is_final or response.is_speech_final:
# The current public Realtime contract does not guarantee increasing
# seq values, so collect final words in arrival order instead of
# asking RealtimeSubtitles to deduplicate by id:seq.
finalized_words.extend(response.words)
def handle_error(error: stt.ErrorResponse | None) -> None:
# The released SDK can invoke a stream handler more than once for one
# routed error, so keep this callback idempotent.
nonlocal server_error
server_error = error
client = stt.RealtimeClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
stream = await client.start_stream(
language=stt.Language.ArEn,
on_response=handle_response,
on_error=handle_error,
)
pcm = input_path.read_bytes()
for offset in range(0, len(pcm), CHUNK_BYTES):
await stream.send(pcm[offset : offset + CHUNK_BYTES])
await asyncio.sleep(0.1)
# close() sends the last frame and waits for protocol is_final, a routed
# error, or this timeout. It returns rather than raising on timeout.
await stream.close(timeout_seconds=5.0)
if server_error is not None:
raise RuntimeError(server_error.message or server_error.code or "Realtime stream failed")
if not protocol_final_observed:
raise RuntimeError("Realtime stream ended before protocol is_final")
output_path.write_text(
stt.Subtitles.from_words(finalized_words).to_vtt(),
encoding="utf-8",
)
if __name__ == "__main__":
asyncio.run(main())
```
يضيف `RtTranscribeResponse` الحقل `is_speech_final` إلى حقول استجابة Fast.
عامله بوصفه نهاية مقطع كلام، واستبدل نص واجهة الاستخدام المؤقت، وأبقِ التدفق
مفتوحًا حتى `is_final` على مستوى البروتوكول.
يرسل `stream.close(timeout_seconds=...)` الإطار النهائي ويعود عند انتهاء انتظار
`is_final` على مستوى البروتوكول. لا يضمن الرجوع وصول `is_final`؛ ولا تنهي
`is_speech_final` ذلك الانتظار. يجمع المثال كلمات
الأحداث النهائية بترتيب الوصول ويعرضها باستخدام `Subtitles`؛ ولا يعتمد على
`seq` لأن ترتيبها وتفرّدها ليسا جزءًا من عقد السلك العام الحالي. يزيل
`RealtimeSubtitles` التكرار حسب `id:seq` وقد يدمج أحداثًا نهائية متميزة. يبقى
سياق العميل مطلوبًا لأن الخطأ الموجه قد يزيل سياق التدفق قبل تشغيل الإغلاق.
## مهمة التمييز: تتبع المتحدثين مباشرة
استخدم `RealtimeDiarizationClient` عندما يحتاج التطبيق إلى خط زمني للمتحدثين
أثناء وصول الصوت. غذِّ واستهلك بالتزامن؛ قد يؤدي انتظار الاستهلاك حتى إرسال
الصوت كله إلى توقف المسار.
### سطح التمييز المنشور
| السطح | عقد `0.18.0` |
|---|---|
| المُنشئ | `RealtimeDiarizationClient(api_url, api_key, api_path=None, verbose=False)` |
| الدوال غير المتزامنة | `connect()`, `start_stream()`, `disconnect()` |
| الدوال المتزامنة | `start_stream_sync()`؛ دالتا التدفق `send_sync()` و`close_sync()` عامتان، لكن `connect_sync()` و`disconnect_sync()` ليستا كذلك |
| خيارات البدء | `language=Language.Ar`، مع استدعاءات الاتصال والتحديث والخطأ |
| التدفق | `stream_id`, `speakers`, `send()` / `send_sync()`, `close(timeout_seconds=5)` / `close_sync()`، وإدارة سياق غير متزامنة، ومكرر غير متزامن واحد. يرفع فشل المكرر `DiarizationStreamError`. |
يُستورد `DIARIZATION_RECOMMENDED_CHUNK_BYTES` من
`humain_voice.stt.constants`، لا من مساحة `stt` العليا. يستقبل هذا البرنامج
التحديثات عبر `on_update` أثناء تغذية الصوت، كي لا تترك مهلة الإغلاق مكررًا
منتظرًا:
```python
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from humain_voice import stt
from humain_voice.stt.constants import DIARIZATION_RECOMMENDED_CHUNK_BYTES
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def main() -> None:
input_path = Path(sys.argv[1] if len(sys.argv) > 1 else "meeting.pcm")
output_path = Path(sys.argv[2] if len(sys.argv) > 2 else "meeting.rttm")
client = stt.RealtimeDiarizationClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
)
async with client:
final_observed = False
def on_update(update: stt.DiarizationUpdate) -> None:
nonlocal final_observed
final_observed = final_observed or update.is_final
for segment in update.newly_finalized:
print(segment.speaker, segment.start_time, segment.end_time)
stream = await client.start_stream(
on_update=on_update,
on_error=lambda error: print("server error:", error),
)
pcm = input_path.read_bytes()
if not pcm or len(pcm) % 2:
raise ValueError("Input must be nonempty PCM16 with an even byte length")
for offset in range(0, len(pcm), DIARIZATION_RECOMMENDED_CHUNK_BYTES):
await stream.send(
pcm[offset : offset + DIARIZATION_RECOMMENDED_CHUNK_BYTES]
)
await asyncio.sleep(0.48)
# close() returns the best-known reconciled timeline after five seconds,
# even when no is_final update arrived. A callback avoids leaving an async
# iterator waiting forever on that timeout path.
timeline = await stream.close(timeout_seconds=5.0)
destination = output_path if final_observed else Path(f"{output_path}.partial")
destination.write_text(stt.to_rttm(timeline, uri="meeting"), encoding="utf-8")
if not final_observed:
print(f"Final result not observed; wrote incomplete output to {destination}")
if __name__ == "__main__":
asyncio.run(main())
```
يعرض كل `DiarizationUpdate` خط `segments` الزمني الموفق كاملًا، و
`newly_finalized` و`active_segments` والاستجابة الخام. ينتظر الإغلاق حتى خمس
ثوان لتحديث نهائي، ويعيد أفضل خط زمني معروف عند انتهاء الانتظار. يكتب المثال
ملف RTTM بلاحقة `.partial` ما لم يرصد `is_final`. يظل خروج السياق مالكًا لتنظيف
العميل.
## مهمة TTS: اكتب ملف WAV قابلًا للتشغيل
استخدم `TTSClient` لاكتشاف صوت وتوليد صوت خام. لا تملك قائمة الأصوات أو
التوليف في Python مهلة ما لم تمرر `timeout_seconds`. تعيد `list_voices()`
قواميس هويات متعددة اللغات بالشكل `{ id, label, profile }`. يحمل `profile`
بيانات `speaker` مشتركة وقائمة `languages` مفتوحة؛ مرر `id` الخاص بالهوية
نفسها في `voice_id`.
في هويات العربية/الإنجليزية الحالية، يختار أي حرف من محارف الكتابة العربية
في `text` النسخة العربية؛ وإلا تُختار الإنجليزية. تبقى معرّفات النسخ الفعلية
داخلية وتُرفض.
### سطح TTS المنشور
| السطح | عقد `0.18.0` |
|---|---|
| المُنشئ | `TTSClient(api_url, api_key, api_path=None, verbose=False, on_connect?, on_error?)`؛ ويبقى ترتيب ما قبل 0.17 `(api_url, api_path, api_key, ...)` مدعومًا مع تحذير إهمال |
| الدوال غير المتزامنة | `connect()`, `list_voices()`, `synthesize()`, `synthesize_stream()`, `close()` |
| الدوال المتزامنة | `list_voices_sync()`, `synthesize_sync()`, `close_sync()`؛ لا توجد `synthesize_stream_sync()` أو`connect_sync()` أو`disconnect_sync()` |
| الخيارات والقيم الافتراضية | يتطلب التوليف نصًا يحتوي بعد إزالة الفراغات على حرف Unicode أو رقم واحد على الأقل، وواحدًا بالضبط من `voice_id` أو`voice_references` غير الفارغة؛ `model=TtsModel.Nebula`؛ والخيارات `timeout_seconds` و`on_audio` للتوليف المخزن و`on_error` و`request_id`. |
| النتيجة | تعيد `list_voices()` قواميس تحمل `id` و`label` و`profile` الاختياري؛ وتحمل استجابات التوليف `id` و`is_last` و`audio: bytes`. |
يرفض هذا البرنامج قائمة أصوات فارغة، ويطبق مهلًا صريحة، ويغلف PCM المعاد في
ترويسة WAV:
```python
from __future__ import annotations
import asyncio
import os
import sys
import wave
from pathlib import Path
from humain_voice import stt, tts
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
def write_pcm16_wav(path: Path, pcm: bytes, sample_rate: int) -> None:
with wave.open(str(path), "wb") as wav_file:
wav_file.setnchannels(1)
wav_file.setsampwidth(2)
wav_file.setframerate(sample_rate)
wav_file.writeframes(pcm)
def handle_error(error: stt.ErrorResponse | None) -> None:
if error is not None:
print("server error:", error.code, error.message)
async def main() -> None:
output_path = Path(sys.argv[1] if len(sys.argv) > 1 else "speech.wav")
async with tts.TTSClient(
api_url=required_env("API_URL"),
api_path=required_env("API_PATH"),
api_key=required_env("API_KEY"),
) as client:
voices = await client.list_voices(timeout_seconds=5.0)
if not voices:
raise RuntimeError("No TTS voices are available")
voice = next((item for item in voices if item.get("profile")), voices[0])
if profile := voice.get("profile"):
print(
"profile:",
voice["label"],
profile["speaker"]["dialect"],
profile["languages"],
)
model = tts.TtsModel.Nebula
pcm = await client.synthesize(
"Hello from HUMAIN Voice",
voice_id=voice["id"],
model=model,
# This is an inactivity timeout applied while awaiting each chunk.
timeout_seconds=30.0,
on_error=handle_error,
)
write_pcm16_wav(output_path, pcm, tts.get_sample_rate(model))
if __name__ == "__main__":
asyncio.run(main())
```
يعيد TTS عبر Socket.IO بايتات PCM16 little-endian خام بتردد 24 kHz وأحادية
القناة. يستخدم المثال وحدة `wave` القياسية لكتابة الحاوية المطابقة. استخدم
`synthesize_stream()` عندما ينبغي للتطبيق معالجة كل مقطع صوتي.
بالنسبة إلى `voice_references`، أرسل مرجعًا واحدًا يكون `audio` فيه RIFF/WAVE
بترميز base64 القياسي ويحتوي بيانات PCM16 أحادية غير فارغة.
ويفرض الخادم بصورة مستقلة مهلة كلية غير قابلة لإعادة الضبط قدرها 25 ثانية
ومراقب خمول قدره 60 ثانية. إذا سبقت المهلة الكلية الإطار النهائي، يكون
`TTS_DEADLINE_EXCEEDED` قابلاً لإعادة المحاولة ويظل الصوت المستلم جزئيًا.
يتلقى استدعاء `on_error` كائن `ErrorResponse` مسوّى؛ تحتفظ الحمولات المنظمة
بـ`code` و`retryable`، وتصبح الحمولة القديمة غير الكائنية رسالة. يرفع كوروتين
التوليف المرفوض `RuntimeError` عامًا يحمل الرسالة فقط، لذلك احتفظ بتفاصيل
الاستدعاء قبل التنظيف. أغلق العميل دائمًا بمدير سياق.
## مهمة إعادة المحاولة: اقرأ نتيجة Batch محفوظة
ينفذ SDK `0.18.0` استدعاء HTTP واحدًا لكل عملية Batch. `max_retries` مهمل
ومتجاهل. يضبط هذا المثال `save_result=True` ثم يعيد قراءة النتيجة المحفوظة
بتراجع محدود، ويستخدم الخاصيتين المنشورتين `status_code` و`retry_after`، ويسجل
السعة. من دون الحفظ، قد تتبع الاستجابة النهائية المفقودة حالة `cleared`؛ ولا
تُحدد مدة احتفاظ حتى عند تفعيل الحفظ.
```python
from __future__ import annotations
import asyncio
import os
import random
import sys
from humain_voice import stt
from humain_voice.stt.batchtranscription import TranscriptionResponse
def required_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"{name} is required")
return value
async def get_result_with_retry(
client: stt.BatchTranscribeClient,
job_id: str,
attempts: int = 5,
) -> TranscriptionResponse:
for attempt in range(1, attempts + 1):
try:
# save_result prevents a terminal read from clearing the stored
# result before a retry. It does not define a retention duration.
return await client.get_result(
job_id, stt.Language.ArEn, save_result=True
)
except stt.BatchTranscribeError as error:
rate_limited = isinstance(error, stt.BatchTranscribeRateLimitError)
retryable = rate_limited or error.retryable is True
print(
{
"status_code": error.status_code,
"code": error.code,
"capacity": error.capacity,
}
)
if not retryable or attempt == attempts:
raise
server_delay = 0
if isinstance(error, stt.BatchTranscribeRateLimitError):
server_delay = error.retry_after or 0
exponential_delay = 0.5 * 2 ** (attempt - 1)
await asyncio.sleep(max(server_delay, exponential_delay) + random.random() * 0.25)
raise RuntimeError("Retry loop exhausted")
async def main() -> None:
if len(sys.argv) < 2:
raise RuntimeError("Pass a batch job ID as the first argument")
async with stt.BatchTranscribeClient(
api_url=required_env("API_URL"),
api_key=required_env("API_KEY"),
) as client:
result = await get_result_with_retry(client, sys.argv[1])
print(result.status.value, result.results.transcript if result.results else "")
if __name__ == "__main__":
asyncio.run(main())
```
لا تستخدم هذه الحلقة نفسها بلا تمييز لإنشاء مهمة. إذا انتهت مهلة الرفع، فقد لا
يعرف التطبيق ما إذا كانت المهمة قد أنشئت.
## المرجع: أنواع النتائج والأخطاء
| النوع | الحقول والسلوك المنشوران |
|---|---|
| `JobResponse` | `job_id` و`status`؛ يبقى اسم البروتوكول `jobId` |
| `TranscriptionResponse` | `status`؛ والحقول الاختيارية `results` و`api_version` و`version` و`metadata` و`diarization_segments` و`error` و`error_code`؛ والخصائص `job_id` و`file_duration` و`is_complete` و`is_failed` و`is_pending`؛ و`subtitles()` |
| `FileUploadedResponse` / `FtTranscribeResponse` | الرفع: `id` و`message` اختياري. نتيجة Fast: `id` و`seq` و`transcription` و`words` و`is_final`، مع `subtitles()`. |
| `RtTranscribeResponse` | حقول Fast مع `is_speech_final` الذي يحدد نهاية مقطع كلام؛ ولا ينهي التدفق إلا `is_final` |
| `DiarizationUpdate` | `id` و`segments` الموفقة و`newly_finalized` و`active_segments` و`is_final` و`raw` |
| `SpeakerContext` / `VoiceProfile` / `VoiceInfo` | `{ gender, dialect }`؛ و`{ speaker, languages }`؛ و`{ id, label, profile? }`. توفر الواجهة الحالية `profile` دائمًا. |
| `VoiceReference` / `TtsAudioResponse` | `{ text, audio }` مع صوت base64؛ و`id` و`is_last` و`audio: bytes`. الحقلان `voice_id` و`voice_references` متنافيان. |
| `ErrorResponse` | الحقول الاختيارية `id` و`message` و`code` و`retryable` و`timestamp` و`retry_after_seconds` و`data` و`reason` و`retry_scope`؛ وتصبح أخطاء Socket.IO القديمة غير الكائنية رسالة |
| استثناءات Batch | يعرض `BatchTranscribeError` القيم `status_code` و`payload` و`code` و`retryable` و`job_id` و`detail` و`timestamp` و`capacity` و`raw_body`؛ وفئاته `BatchTranscribeAuthError` و`BatchTranscribeTimeoutError` (`elapsed_seconds`) و`BatchTranscribeJobFailedError` (`error`، `error_code`) و`BatchTranscribeRateLimitError` (`retry_after`). |
| مسارات فشل Socket.IO | تستدعي أخطاء Fast الموجهة `on_error` ثم ترفع `RuntimeError` يحمل الرسالة فقط؛ ويشير Realtime إلى استدعائه وانتظاره النهائي؛ ويرفع مكرر التمييز `DiarizationStreamError`؛ وتحافظ أخطاء TTS الموجهة على الاستدعاء المنظم لكن التوليف يرفع `RuntimeError` يحمل الرسالة فقط. قد يصل الخطأ غير القابل للتوجيه إلى الاستدعاء العام فقط، لذلك احتفظ بمهلة للتطبيق ونظف دائمًا. |
## المرجع: الاستيرادات وثوابت الأحداث
يصدر `BatchDiarization` و`BatchRedact` و`AudioInput` الدفعي وأنواع استجابة
Batch من `humain_voice.stt.batchtranscription`، لا من مساحة
`humain_voice.stt` العليا. يتوفر `BatchTranscriptionModel` عبر `stt`.
يصدر TTS القيم `TtsModel` و`DEFAULT_SAMPLE_RATE` و`MODEL_SAMPLE_RATES` و
`get_sample_rate()` و`decode_tts_audio_frame()`.
| مسار الاستيراد | ثوابت الأحداث العامة وقيم البروتوكول |
|---|---|
| `humain_voice.stt.constants` | `EVENT_FT_ERROR="error"`, `EVENT_FT_TRANSCRIBE_FILE="audio_file"`, `EVENT_FT_TRANSCRIBE_FILE_UPLOAD_SUCCESS="audio_file_upload_success"`, `EVENT_FT_TRANSCRIBE_RESULT="transcription_result"` |
| `humain_voice.stt.constants` | `EVENT_RT_AUDIO_STREAM="audio_stream"`, `EVENT_RT_END_AUDIO_STREAM="end_audio_stream"` |
| `humain_voice.stt.constants` | `EVENT_DIARIZATION_STREAM="diarization_stream"`, `EVENT_DIARIZATION_RESULT="diarization_result"` |
| `humain_voice.tts` | `EVENT_TTS_REQUEST="tts"`, `EVENT_TTS_AUDIO="tts_audio"`, `EVENT_TTS_ERROR="error"`, `EVENT_TTS_VOICE_LIST_REQUEST="tts_voice_list"`, `EVENT_TTS_VOICE_LIST_RESULT="tts_voice_list_result"` |
تصدّر `humain_voice.errors` ثوابت رموز الخطأ الكبيرة نفسها المدرجة في دليل
JavaScript. كما تصدّر `is_asr_code()` و`is_tts_code()` و
`is_request_scoped_code()` و`is_realtime_owned()` و`is_tts_owned()` و
`is_diarization_code()` و`is_diarization_owned()` لتوجيه أخطاء Socket.IO
المنظمة. لا تعيد مساحة `humain_voice.stt` العليا تصدير ثوابت أحداث STT.
## المرجع: مساعدات الترجمات
| API | عقد `0.18.0` |
|---|---|
| `Subtitles` | الأنواع `SubtitleCue` و`SubtitleOptions` و`SubtitleError`؛ المُنشئ و`cues`؛ و`from_words` و`from_cues` و`from_response`؛ و`to_srt` و`to_vtt` |
| `RealtimeSubtitles` | `words` و`cues` و`add_response` و`subtitles` و`to_srt` و`to_vtt`؛ يتجاهل المؤقت ويزيل تكرار استجابات `id:seq` النهائية |
| المساعدات العليا | `words_to_cues` و`cues_to_srt` و`cues_to_vtt` و`subtitles` و`to_srt` و`to_vtt` |
| قيم التشكيل الافتراضية | `max_duration_seconds=6`، و`max_gap_seconds=0.7`، و`min_duration_seconds=0.5`، و`max_chars_per_line=42`، و`max_lines=2`، و`split_on_speaker_change=True`، و`strict=False`؛ و`start_index=1` في SRT |
يقبل دخل الترجمات إزاحات كلمات Batch ومقاطع كلمات Realtime. فعّل الوضع الصارم
عندما يجب أن يفشل التوقيت غير الصالح أو غير المرتب بدل تسويته أو تخطيه.
## الخطوات التالية
---
# مرجع حدث النسخ السريع
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/asyncapi/fast-transcription
يرفع حدث `audio_file` ملفًا كاملًا عبر Socket.IO كحمولة ثنائية واحدة. يرد
الخادم بإقرار رفع ثم أحداث `transcription_result` جزئية ونهائية. أسماء الحقول
والنماذج تبقى كما هي في البروتوكول.
## الاتصال
- المسار: `/socket.io`
- النقل: `websocket` فقط
- المصادقة: ترويسة `x-api-key`
- ترويسة `Origin`: مطلوبة على الإنتاج؛ اضبطها على `https://api.voice.humain.com`
## الحدود
ينطبق حدّان مستقلان على كل رفع لحدث `audio_file`، وهما يقيسان أمرين مختلفين.
وكلاهما شامل: النجاح عند الحد بالضبط، والفشل عند تجاوزه فقط.
| الحد | القيمة | رمز التجاوز | `data.bound` | الاتصال |
|------|--------|--------------|--------------|---------|
| بايتات الوسائط المُرمَّزة | 64 MiB (`67108864`) | `PAYLOAD_TOO_LARGE` | `fast_audio_bytes` | يُغلق |
| مدة الصوت بعد فك الترميز | 1800 ثانية (30 دقيقة) | `AUDIO_DURATION_EXCEEDED` | `fast_audio_duration` | يبقى مفتوحًا |
يُقاس سقف البايتات على بايتات الوسائط وحدها، بعد ترويسة التأطير وسلاسل مفاتيح
النماذج الأربعة. أما مسار HTTP المكافئ فيحدّ جسم طلب multipart كاملًا بالرقم
نفسه، لذلك يمر ملف بحجم 64 MiB بالضبط هنا لكنه لا يتسع داخل جسم HTTP بحجم
64 MiB.
ويُغلق تجاوز سقف البايتات الاتصال، لأن النقل خزّن حمولة مفرطة الحجم فعلًا فلا
يبقى المقبس متاحًا لتكرارها. أما تجاوز حد المدة فلا يغلق الاتصال: فلم يُخزَّن
شيء مفرط الحجم، ويحتفظ العميل الذي يجري عمليات نسخ أخرى على المقبس نفسه بها.
ويُرفض الصوت المفرط في الطول قبل أي استدلال ولا يستهلك أي رصيد من سعة الصوت.
وللتسجيلات الأطول من 30 دقيقة أو الأكبر من 64 MiB، قسّم الصوت إلى وحدات أقصر
أو استخدم واجهة النسخ الدفعي التي يبلغ سقفها 4 ساعات لكل ملف.
لا يعني `audio_file_upload_success` أن الصوت قد قُبِل. فهو يقر باستلام الحدث
ونجاحه في الفحوص التي يمكن إجراؤها من البايتات وحدها: التأطير، وسقف البايتات،
والمدة التي تعلنها ترويسة WAV عن نفسها. أما الفحوص الباقية — قائمة الحاويات
المسموح بها، ومدة البيانات الوصفية للحاوية، وفك الترميز المحدود المرجعي — فتجري
بعده، لذلك يستقبل رفعٌ مضغوط يُفك إلى أكثر من 1800 ثانية، أو حاوية خارج
المجموعة المقبولة، الحدث `audio_file_upload_success` ثم حدث `error`. عامل هذا
الحدث كإيصال على مستوى البايتات، لا كقبول. ووحده `transcription_result` مع
`is_final: true` يعني أن الصوت قد نُسخ.
## تنسيق الصوت
يجب أن تكون الحمولة الكاملة AAC (ADTS) أو FLAC أو MP3 أو WAV أو ملف ISO base
media. ويتعرف الخادم على الحاوية من الحمولة نفسها، لا من اسم ملف ولا من نوع
وسيط، ويُرفض أي شيء آخر بالرمز `ASR_UNSUPPORTED_CODEC` حتى عندما يكون قابلًا
لفك الترميز.
ومدخل ISO base media عائلة: فصيغة MP4 هي الشكل المقصود والمدعوم، أما MOV وM4A
و3GP و3G2 وMJ2 فتشترك معها في مفكك حاويات واحد ولذلك يقبلها الفحص نفسه. وMP4
وحدها مدعومة بمعنى أنها مختبرة ومقصودة؛ فلا تبنِ على غيرها.
وضع الذرة `moov` في مقدمة ملف ISO base media. وهذه ليست سياسة يفحصها الخادم
ويرفض على أساسها — بل مطلب عملي: فالرفع يُقرأ إلى الأمام فقط، ولا يمكن الوصول
إلى `moov` في نهايته فيفشل فك ترميز الملف.
## اللغات والنماذج
| القيمة | المفتاح | المعنى |
|--------|---------|--------|
| `0` | `ar` | العربية |
| `1` | `en` | الإنجليزية |
| `2` | `codeswitch` | تبديل عربي-إنجليزي |
| النموذج | اللغة | الاستخدام |
|---------|-------|-----------|
| `nida_ar` | العربية | ASR عربي |
| `nida_8k_ar` | العربية | ASR عربي لاتصالات 8 kHz |
| `bayan_ar` | العربية | ASR عربي موصى به |
| `fast_en` | الإنجليزية | ASR إنجليزي |
| `bayan_cs_ar_en` | عربي-إنجليزي | اسم مستعار لأحدث نموذج تبديل مستقر |
| `bayan_cs_ar_en_v1` | عربي-إنجليزي | إصدار v1 مثبت |
| `bayan_cs_ar_en_v2` | عربي-إنجليزي | إصدار v2 مثبت |
المفاتيح التي لا تنتهي بـ `_vN` أسماء مستعارة قد تتحرك إلى إصدار مستقر أحدث.
استخدم مفاتيح `_vN` عندما تحتاج إلى سلوك قابل للتكرار.
## الأحداث
| الحدث | الاتجاه | المعنى |
|-------|---------|--------|
| `audio_file` | العميل إلى الخادم | رفع ملف صوتي كامل للنسخ. |
| `audio_file_upload_success` | الخادم إلى العميل | إيصال باستلام البايتات ومعرّف الطلب؛ وليس قبولًا للصوت. |
| `transcription_result` | الخادم إلى العميل | نتيجة نسخ جزئية أو نهائية. |
| `error` | الخادم إلى العميل | خطأ منظم. |
## تخطيط `audio_file`
حقول الطول تستخدم `uint16` بترتيب little-endian. اضبط طول أي مفتاح نموذج إلى
`0` لتجاوزه.
## مثال إرسال
```ts
socket.emit("audio_file", packet);
socket.on("audio_file_upload_success", ({ id }) => {
// إيصال بايتات فقط؛ انتظر transcription_result مع is_final للتأكد من النسخ.
console.log("received", id);
});
socket.on("transcription_result", (response) => {
console.log(response.transcription, response.is_final);
});
```
## نتيجة النسخ
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "مرحبا بكم",
"words": [
{ "start_time": 0.0, "end_time": 1.1, "word": "مرحبا" },
{ "start_time": 1.1, "end_time": 2.4, "word": "بكم" }
],
"is_final": true
}
```
الحقول `id` و`seq` و`transcription` و`words` و`is_final` كلها مطلوبة. توجد
أزمنة `start_time` و`end_time` داخل كل عنصر في `words` فقط، لا على المستوى
الأعلى. عامل `seq` بوصفه بيانات تشخيصية؛ فترتيبها وتجميعها ليسا جزءًا من عقد
Fast العام.
## الأخطاء
استخدم حدث `error` لالتقاط فشل المصادقة، أو payload غير صالح، أو تجاوز أحد
الحدود. وحقل `code` معدود؛ فرّع عليه لا على نص الرسالة:
| `code` | المعنى |
|--------|--------|
| `AUTH_FORBIDDEN` | مفتاح API لا يمنح الصلاحية |
| `VALIDATION_INVALID_FORMAT` | تأطير أو نوع بيانات غير صالح |
| `VALIDATION_INVALID_LANGUAGE` | قيمة لغة غير معروفة |
| `VALIDATION_FILE_CORRUPT` | صوت تالف أو غير قابل لفك الترميز |
| `PAYLOAD_TOO_LARGE` | تجاوز سقف بايتات الوسائط |
| `AUDIO_DURATION_EXCEEDED` | تجاوز حد المدة بعد فك الترميز |
| `ASR_UNSUPPORTED_CODEC` | حاوية خارج المجموعة المنشورة |
| `ASR_MODEL_NOT_FOUND` | مفتاح نموذج ASR غير مضبوط |
| `SESSION_BYTES_EXCEEDED` | تجاوز بايتات الجلسة المتراكمة |
| `SESSION_DURATION_EXCEEDED` | تجاوز مدة الجلسة بالزمن الحقيقي |
| `SESSION_IDLE_TIMEOUT` | انقضت مهلة سكون الجلسة |
| `ASR_TRANSCRIPTION_FAILED` | فشل النسخ في الخلفية |
ويحمل رفض الحدود كائن `data` يسمّي الحد وقيمته المضبوطة والقيمة المرصودة، حتى
تعرف أي حد بلغته دون تحليل نص. ولحد `fast_audio_duration` تكون `unit` هي
`seconds`، وحيث توقفت الخدمة عن فك الترميز عند السقف تكون `observed` حدًا أدنى.
ولحد `fast_audio_bytes` تكون `unit` هي `bytes` و`observed` هي حجم الوسائط
الدقيق.
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "AUDIO_DURATION_EXCEEDED",
"message": "decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z",
"data": {
"limit": 1800,
"observed": 3601,
"unit": "seconds",
"bound": "fast_audio_duration"
}
}
```
---
# مرجع أحداث Realtime STT
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/asyncapi/realtime
يصف هذا المرجع أحداث Socket.IO التي تستقبل مقاطع صوت PCM16 عبر `audio_stream`
و`diarization_stream` وتعيد نتائج النسخ أو تمييز المتحدثين. أسماء الأحداث
والحقول الثنائية تبقى كما هي في البروتوكول.
## الاتصال
- المضيف الإنتاجي: `https://api.voice.humain.com`
- المسار: `/socket.io`
- النقل: `websocket` فقط
- المصادقة: ترويسة `x-api-key`
- ترويسة `Origin`: مطلوبة على الإنتاج؛ اضبطها على `https://api.voice.humain.com`
```ts
import { io } from "socket.io-client";
const socket = io("https://api.voice.humain.com", {
path: "/socket.io",
transports: ["websocket"],
extraHeaders: {
"x-api-key": process.env.API_KEY!,
Origin: "https://api.voice.humain.com",
},
});
```
## اللغات
| القيمة | المفتاح | المعنى |
|--------|---------|--------|
| `0` | `ar` | العربية |
| `1` | `en` | الإنجليزية |
| `2` | `codeswitch` | تبديل عربي-إنجليزي |
| `255` | `auto` | تلقائي؛ يُحل إلى الافتراضي المضبوط للبيئة |
## الحدود
تنطبق أربعة حدود على الجلسة الفورية. وكلها شاملة: النجاح عند الحد بالضبط،
والفشل عند تجاوزه فقط.
**لكل حدث: 16 MiB.** يجب ألا يتجاوز حدث `audio_stream` أو `diarization_stream`
واحد `16777216` بايت، محتسبةً ترويسة 18 بايتًا. وتجاوزه يصدر
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `realtime_asr_frame_bytes` أو
`realtime_diarization_frame_bytes`، ثم يغلق الاتصال. وهذا مطابق للسقف الذي
تفرضه مسارات HTTP المكافئة أصلًا.
**لكل جلسة، إجمالي المحتوى الصوتي: 14400 ثانية (4 ساعات).** وهو الصوت المقبول
المتراكم، وهو كمية مختلفة عن المدة التي بقيت فيها الجلسة مفتوحة. وتجاوزه يصدر
`AUDIO_DURATION_EXCEEDED` مع `data.bound: session_audio_duration` ويُنهي
الجلسة؛ فابدأ جلسة جديدة.
**لكل جلسة، معدل الصوت: أربعة أضعاف الزمن الحقيقي.** يمكن أن يصل الصوت بما يبلغ
`128000` بايت في الثانية، مع سماح اندفاع 16 MiB — وهو إطار بالحجم الأقصى.
والعميل الذي يبث بالزمن الحقيقي فعلًا يستخدم ربع حصته ولا يمكن أن يبلغ هذا
الحد؛ أما العميل الذي يعوّض تأخرًا بعد تعطل شبكي فيفرّغ متأخراته بثلاثة أضعاف
الزمن الحقيقي. وتجاوزه يصدر `SESSION_BYTE_RATE_EXCEEDED` مع
`data.bound: session_audio_rate_burst` ومع `retry_after_seconds` (فليس لهذا
النقل ترويسة `Retry-After`، لذلك يسافر الانتظار داخل الإطار)، ولا يغلق الاتصال:
فتنجح الحمولة نفسها بمجرد أن يُعاد ملء الرصيد. ولا يستهلك الرفض أي رصيد ولا أي
حصة.
وسعة الدلو تغطي دائمًا أكبر إطار تقبله الواجهة، لذلك لا يُرفض إطار بالحجم
الأقصى أبدًا بسبب حد المعدل على جلسة بدأت للتو. أما على Socket.IO فالدلو يخص
الاتصال وتتشاركه كل أحداث الصوت عليه، لذلك قد يُحدَّد معدل إطار بالحجم الأقصى
أُرسل على اتصال بث صوتًا فعلًا؛ فالتزم بـ`retry_after_seconds` وأعد إرساله دون
تغيير.
ولم تتغير حدود الجلسة الخاصة بالبايتات المتراكمة ولا بالمدة بالساعة الحقيقية
ولا بالسكون.
## أخطاء الرصيد والفوترة
يحجز تدفق ASR الفوري رصيدًا قابلًا للتجديد عند البدء، ثم يجدد الحجز أثناء
التشغيل. وتُبلّغ النتيجتان التاليتان بالرموز نفسها عبر كل وسائل النقل وHTTP:
- `CREDITS_EXHAUSTED`: نفد رصيد الحساب. يقابله HTTP 402 و`retryable: false`،
لأن الإعادة الفورية لا تستعيد الرصيد.
- `BILLING_AUTHORIZATION_UNAVAILABLE`: تعذر الوصول إلى جهة اعتماد الفوترة أو
لم تعطِ قرارًا حاسمًا، لذلك يفشل الطلب بأمان. يقابله HTTP 503 و`retryable:
true`؛ أعد المحاولة بعد الانتظار.
قد يصل الخطأ عند بدء التدفق إذا رُفض الحجز، أو في منتصفه إذا رُفض تجديده أثناء
وصول الصوت. والخطأ في منتصف التدفق نهائي لذلك التدفق: يتوقف الخادم عن قبول
الصوت المدفوع، ويرسل حدث `error` النهائي أولًا، ثم يفصل الاتصال. ويُحاسب فقط
الصوت المقبول قبل الخطأ. أما رفض الحجز عند البدء فلا يغلق الاتصال، لأن المقبس
قد يحمل عمليات أخرى.
في واجهة WebSocket الخام يحمل إطار الإغلاق رمزًا خاصًا يساوي `4000 + HTTP
status`: الرمز `4402` لنفاد الرصيد و`4503` لتعذر اعتماد الفوترة. ولا تحمل
واجهة Socket.IO رمز إغلاق على مستوى التطبيق؛ لذا يكون حدث `error` المنظم هو
الإشارة المعتمدة، وليس رمز الإغلاق.
## التحقق من الإطار
يُتحقق من كل إطار قبل أي عمل للنموذج. ويُرفض الإطار عندما يكون أقصر من ترويسته
البالغة 18 بايتًا، أو عندما يكون UUID تدفقه أصفارًا كلها، أو عندما يضبط بت راية
غير معرَّف في تخطيط تلك الواجهة، أو عندما لا يكون بايت لغته أحد `0` أو `1`
أو `2` أو `255`، أو عندما يكون صوته فارغًا، أو عندما يكون طول صوته فرديًا.
ويُجاب على الإطار المقطوع، ولا يُقبل صامتًا أبدًا. وكل هذه أخطاء إدخال قابلة
للإصلاح من جهة العميل، ولا يُبلَّغ عن أي منها كخطأ خادم.
## الأحداث
| الحدث | الاتجاه | المعنى |
|-------|---------|--------|
| `audio_stream` | العميل إلى الخادم | مقطع صوت للنسخ الفوري. |
| `speaker_id` | العميل إلى الخادم | قديم؛ يعيد الخادم `METHOD_NOT_ALLOWED`. |
| `transcription_result` | الخادم إلى العميل | نتيجة نسخ جزئية أو نهائية. |
| `speaker_id_result` | الخادم إلى العميل | قديم؛ لا يصدر الخادم هذا الحدث. |
| `diarization_stream` | العميل إلى الخادم | مقطع صوت لتمييز المتحدثين. |
| `diarization_result` | الخادم إلى العميل | مقاطع المتحدثين النهائية أو النشطة. |
| `error` | الخادم إلى العميل | خطأ منظم. |
## إطار `audio_stream`
أرسل المقطع الأول مع `is_start`، والمقاطع الوسطية بلا رايات، والمقطع الأخير مع
`is_final`. عندما تكون `diarization_enabled` مفعّلة، ينسخ الخادم الصوت ويرسل
أيضًا أحداث `diarization_result`.
أرسل 1,600 عينة، أي 100 ms، في المقطع الموصى به. يخزن ASR المقاطع الأقصر حتى
1,600 عينة ويجزئ المقاطع الأطول إلى وحدات بهذا الحجم؛ ولا تنطبق قواعد التخزين
هذه على `diarization_stream`. يمكن لاتصال واحد حمل عدة تدفقات: أعد استخدام UUID
نفسه لتدفق واحد، واستخدم UUID جديدًا لكل تدفق جديد.
## نتيجة النسخ
تصل `transcription_result` عادة بالشكل التالي:
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"seq": 0,
"transcription": "مرحبا بكم",
"words": [
{ "start_time": 0, "end_time": 1.2, "word": "مرحبا بكم" }
],
"is_final": false,
"is_speech_final": true
}
```
تمثل `is_speech_final: true` حد نهاية كلام ويمكن أن يستمر التدفق بعده. ولا ينتهي
التدفق كله إلا عند `is_final: true`. عامل `seq` بوصفه قيمة تشخيصية؛ فلا يضمن
العقد العام ترتيبها أو تفرّدها.
## إطار `diarization_stream`
يستخدم `diarization_stream` تخطيط البايتات نفسه المستخدم في `audio_stream`، لكن
مجموعة الرايات ليست نفسها: إطار تمييز المتحدثين يعرّف `bit 0` و`bit 1` فقط، أما
البتات المحجوزة 2..7 فيجب أن تكون أصفارًا، ويُرفض أي إطار يضبط أيًا منها. ولا
تضبط `bit 2` هنا؛ فراية `diarization_enabled` تخص `audio_stream` وحده. ونموذج
تمييز المتحدثين يحل من `model_config` في جهة الخادم، لذلك يكون حقل اللغة موجودًا
للاتساق فقط، وأرسله صفرًا.
## نتيجة تمييز المتحدثين
تحتوي `diarization_result` على مقاطع نهائية ونشطة:
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"is_final": false,
"final_segments": [
{ "speaker": "SPEAKER_00", "start_time": 0, "end_time": 1.5 }
],
"active_segments": [
{ "speaker": "SPEAKER_01", "start_time": 1.5, "end_time": 3 }
]
}
```
## الأخطاء
حمولة الحدث `error` كائن JSON منظم، وحقول `code` و`message` و`retryable`
و`timestamp` كلها مطلوبة فيه. فرّع على `code` المعدود لا على نص `message`؛
فـ`message` يحمل النص الحر نفسه الذي كان يُرسل سابقًا سلسلةً مجردة:
```json
{
"code": "VALIDATION_INVALID_FORMAT",
"message": "Invalid data type",
"retryable": false,
"timestamp": "2025-05-07T10:00:00.000Z"
}
```
| `code` | المعنى |
|--------|--------|
| `AUTH_FORBIDDEN` | مفتاح API لا يمنح الصلاحية |
| `VALIDATION_INVALID_FORMAT` | تأطير أو نوع بيانات غير صالح |
| `VALIDATION_INVALID_LANGUAGE` | قيمة لغة غير معروفة |
| `VALIDATION_INVALID_UUID` | UUID تدفق غير صالح |
| `VALIDATION_FILE_CORRUPT` | صوت تالف أو غير قابل لفك الترميز |
| `VALIDATION_REQUIRED_FIELD` | حقل مطلوب مفقود |
| `PAYLOAD_TOO_LARGE` | تجاوز الإطار سقف 16 MiB |
| `AUDIO_DURATION_EXCEEDED` | تجاوزت الجلسة حصتها الصوتية |
| `SESSION_BYTE_RATE_EXCEEDED` | الصوت يصل أسرع مما يسمح به معدل الجلسة |
| `SESSION_BYTES_EXCEEDED` | تجاوز بايتات الجلسة المتراكمة |
| `SESSION_DURATION_EXCEEDED` | تجاوز مدة الجلسة بالزمن الحقيقي |
| `SESSION_IDLE_TIMEOUT` | انقضت مهلة سكون الجلسة |
| `SESSION_EXPIRED` | الجلسة غير حيّة؛ ابدأ جلسة جديدة |
| `SESSION_SLOTS_EXHAUSTED` | استُنفدت خانات الجلسات المتزامنة للحساب |
| `CONCURRENCY_LIMIT_EXCEEDED` | بلغ الحساب حد العمليات المتزامنة في خطته |
| `CREDITS_EXHAUSTED` | نفد رصيد الحساب؛ لا تفِد الإعادة الفورية |
| `BILLING_AUTHORIZATION_UNAVAILABLE` | تعذر التحقق من الفوترة؛ أعد المحاولة بعد الانتظار |
| `ASR_TRANSCRIPTION_FAILED` | فشل النسخ في الخلفية |
| `ASR_STREAM_EXPIRED` | انتهى تدفق ASR؛ افتح تدفقًا جديدًا ولا تعد استخدام معرّفه |
| `DIARIZATION_FAILED` | فشل تمييز المتحدثين في الخلفية |
| `DIARIZATION_MODEL_NOT_FOUND` | نموذج تمييز المتحدثين غير مضبوط |
| `METHOD_NOT_ALLOWED` | حدث مهجور، مثل `speaker_id` |
ويحمل رفض الحدود كائن `data` يسمّي الحد وقيمته المضبوطة والقيمة المرصودة. أما
رفض الحدود القابل لإعادة المحاولة فيحمل أيضًا `retry_after_seconds`:
```json
{
"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": 8,
"observed": 8,
"unit": "operations",
"bound": "account_concurrency_realtime_asr"
}
}
```
حد العمليات المتزامنة لكل حساب قابل للفوترة، لذلك تتشارك عدة مفاتيح API تابعة
لحساب واحد حصة واحدة. ولا يُغلق الاتصال: فالعمليات الأخرى المقبولة عليه تبقى
تعمل.
ويحمل `ASR_STREAM_EXPIRED` كذلك `reason` بقيمة `audio_inactivity` أو
`backend_sequence_lost`، ويحمل `retry_scope: "new_stream"`. افتح تدفقًا
جديدًا بمعرّف UUID جديد، ولا تعاود الإرسال على المعرّف المنتهي:
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"code": "ASR_STREAM_EXPIRED",
"message": "realtime ASR stream expired",
"retryable": true,
"timestamp": "2026-01-15T10:30:00Z",
"reason": "audio_inactivity",
"retry_scope": "new_stream"
}
```
---
# مرجع أحداث TTS
Locale: ar
Source: https://docs.voice.humain.com/ar/api-guides/asyncapi/tts
يستقبل TTS حدث `tts` بحمولة JSON ويبث الصوت عبر `tts_audio`. يمكن أيضًا طلب
قائمة الأصوات باستخدام `tts_voice_list` واستلام `tts_voice_list_result`.
## الاتصال
- المسار: `/socket.io`
- النقل: `websocket` فقط
- المصادقة: ترويسة `x-api-key`
- ترويسة `Origin`: مطلوبة على الإنتاج؛ اضبطها على `https://api.voice.humain.com`
## التدفق
## الأحداث
| الحدث | الاتجاه | المعنى |
|-------|---------|--------|
| `tts` | العميل إلى الخادم | طلب توليد كلام من نص. |
| `tts_audio` | الخادم إلى العميل | مقطع صوت ثنائي. |
| `tts_voice_list` | العميل إلى الخادم | طلب قائمة الأصوات. |
| `tts_voice_list_result` | الخادم إلى العميل | الهويات السبع متعددة اللغات المتاحة. |
| `error` | الخادم إلى العميل | خطأ منظم. |
## حمولة `tts`
```json
{
"id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
"text": "مرحبًا من HUMAIN Voice",
"model": "nebula",
"voice_id": "af52a907-1086-46f7-8f5d-72317875d7bd"
}
```
`voice_id` و`voice_references` اختياريان ومتعارضان. استخدم `voice_id` عندما
تختار صوتًا من المكتبة، واستخدم `voice_references` لتكييف الصوت من مراجع صوتية.
## حدود النص
يُحسب طول `text` بنقاط ترميز Unicode، لا ببايتات UTF-8 ولا بعناقيد المحارف
المعروضة؛ وتُحفظ المسافات في البداية والنهاية وتُحسب. والافتراضيات الشاملة هي
500 نقطة ترميز للحسابات المجانية و1,000 للقياسية والمؤسسية، وتستخدم الفئات
المفقودة أو غير المعروفة الحد المجاني.
- النص الفارغ أو المكوّن من مسافات فقط يصدر `VALIDATION_REQUIRED_FIELD` غير
قابل لإعادة المحاولة.
- النص الذي لا يحتوي حرفًا ولا رقمًا، مثل علامات ترقيم فقط، يصدر
`VALIDATION_INVALID_PARAM` غير قابل لإعادة المحاولة.
- النص الذي يتجاوز الحد الفعلي يصدر `CHARACTER_COUNT_EXCEEDED` غير قابل لإعادة
المحاولة، ويحمل `data` مع `bound` بقيمة `tts_input_characters`.
ويجري التحقق قبل التصنيع وقبل خصم دلو حد المعدل لكل مفتاح.
`text` نص UTF-8 عادي وليس SSML. فلا يُحلَّل الترميز ولا يُتحقق منه: أقواس
الزوايا لا تحمل أي معنى، وتُحسب في حد الأحرف كأي محارف أخرى، وقد يُنطَق اسم
الوسم.
## سياسة المحتوى
عندما يكون فرض سياسة المحتوى مفعّلًا، يصدر النص المرفوض
`TTS_INPUT_NOT_ALLOWED` غير القابل لإعادة المحاولة؛ غيّر النص قبل المحاولة
مجدّدًا. وإذا تعذر على جهة الإشراف على المحتوى اتخاذ قرار، يفشل التوليف بصورة
مغلقة مع `TTS_MODERATION_UNAVAILABLE` القابل لإعادة المحاولة. يفصل العقد بين
الحالتين حتى لا يظهر فشل البنية التحتية بوصفه محتوى محظورًا، وتصدر كلتاهما قبل
بدء التوليف.
## حدود المرجع الصوتي
يقبل `voice_references` عنصرًا واحدًا بالضبط، ويُفحص كل حد عليه قبل البحث عن
النموذج وقبل حجز التزامن وقبل خصم حد المعدل، لذلك لا يستهلك الطلب المرفوض أي
حصة ولا أي خانة:
| الحالة | `code` | `bound` |
|--------|--------|---------|
| أكثر من عنصر واحد | `VOICE_REFERENCE_COUNT_EXCEEDED` | `tts_voice_reference_count` |
| نص مرجع يتجاوز حده (الافتراضي 500 نقطة ترميز، مستقل عن ميزانية `text`) | `CHARACTER_COUNT_EXCEEDED` | `tts_voice_reference_text_characters` |
| صوت مرجعي يتجاوز سقف البايتات بعد فك الترميز (الافتراضي 2 MiB) | `PAYLOAD_TOO_LARGE` | `tts_voice_reference_bytes` |
| صوت مرجعي أطول من سقف المدة (الافتراضي 15 ثانية) | `AUDIO_DURATION_EXCEEDED` | `tts_voice_reference_duration` |
| مصفوفة فارغة صريحة | `VALIDATION_INVALID_PARAM` | — |
| إرسال `voice_id` مع `voice_references` | `VALIDATION_INVALID_PARAM` | — |
| base64 غير قانوني بصرامة، أو صوت ليس PCM16 أحادي القناة بصيغة RIFF/WAVE | `VALIDATION_INVALID_FORMAT` | — |
ويُفحص سقف البايتات من طول base64 قبل فك ترميز الحمولة، لذلك لا يُنشأ المرجع
المفرط في الحجم أبدًا. وسقف المدة مطابق لحد المرجع في النموذج المنشور نفسه.
حذف الحقل، أو إرسال `null`، كلاهما يعني «لا مرجع»، ولذلك فإن `voice_id` مع
`voice_references: null` صالح ويستخدم `voice_id`. أما المصفوفة الفارغة الصريحة
`[]` فهي مصفوفة صحيحة التكوين تخالف `minItems: 1` المعلن، ولذلك تُرفض.
ويمكن للنشر أن يخفض سقوف المرجع عبر
`TTS_MAX_VOICE_REFERENCE_DECODED_BYTES` و`TTS_MAX_VOICE_REFERENCE_DURATION_SEC`
و`TTS_MAX_VOICE_REFERENCE_TEXT_CHARACTERS`، لكنه لا يستطيع أبدًا رفعها فوق
الافتراضيات المنشورة.
## تخطيط `tts_audio`
```ts
socket.on("tts_audio", (buf: ArrayBuffer) => {
const bytes = Buffer.from(buf);
const isFinal = (bytes[16] & 0x01) === 1;
const audio = bytes.subarray(17);
});
```
ناتج TTS هو موجة PCM خامة وليس WAV. أضف ترويسة WAV إذا أردت حفظ ملف قابل
للتشغيل مباشرة.
## قائمة الأصوات
```ts
socket.emit("tts_voice_list");
socket.on("tts_voice_list_result", (response) => {
for (const voice of response) {
console.log(voice.id, voice.label, voice.profile);
}
});
```
تعيد القائمة هويات متعددة اللغات فقط؛ ولا تعرض معرّفات النسخ الفعلية أو
تقبلها في `voice_id`. يختار وجود أي حرف من محارف الكتابة العربية في `text`
النسخة العربية؛ وإلا تُختار الإنجليزية.
## الأخطاء
قد تعاد أخطاء المصادقة، أو نموذج غير معروف، أو صوت غير صالح، أو ضغط السعة، أو
تجاوز أحد الحدود عبر حدث `error`. استخدم `code` أو `error` للتفرّع الآلي
و`message` للتشخيص.
عامل `TTS_INPUT_NOT_ALLOWED` بوصفه رفضًا غير قابل للإعادة للنص نفسه، وعامل
`TTS_MODERATION_UNAVAILABLE` بوصفه فشلًا عابرًا قابلًا للإعادة بعد تراجع محدود.
لا تستنتج من تعذر الإشراف أن النص خالف السياسة.
ويُحل `voice_id` المُرسَل قبل أي خصم حصة أو رسم حد معدل أو استدلال، وأخطاؤه
مُصنَّفة (SAU-2258): فـ`voice_id` الذي ليس UUID صالحًا يُصدر
`VALIDATION_INVALID_UUID` غير القابل لإعادة المحاولة؛ و`voice_id` صالح البنية
لكنه لا يحدد صوتًا متاحًا يُصدر `TTS_VOICE_NOT_FOUND` غير القابل لإعادة المحاولة؛
وصوت محلول بياناته المخزَّنة ناقصة أو تالفة يُصدر `TTS_VOICE_RESOLUTION_FAILED`
غير القابل لإعادة المحاولة؛ وانقطاع عابر مصنَّف إيجابيًا لقاعدة البيانات/التخزين
أثناء الحل يُصدر `SERVER_DEPENDENCY_FAILURE` القابل لإعادة المحاولة. ولأن الحل
يسبق أي محاسبة، فإعادة محاولة الحالة القابلة لإعادة المحاولة آمنة.
ويحمل رفض الحدود كائن `data` يسمّي الحد وقيمته المضبوطة والقيمة المرصودة. أما
حالات الرفض القابلة لإعادة المحاولة فتحمل أيضًا `retry_after_seconds`، لأن هذا
النقل لا ترويسة `Retry-After` فيه:
```json
{
"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"
}
}
```
حد العمليات المتزامنة لكل حساب قابل للفوترة، لذلك تتشارك عدة مفاتيح API تابعة
لحساب واحد حصة واحدة. ولا يُغلق الاتصال: فالعمليات الأخرى المقبولة عليه تبقى
تعمل.
---
# Direct HTTP API Reference
Locale: en
Source: https://docs.voice.humain.com/en/api-reference
Use this reference when you need exact HTTP paths, parameters, request bodies, response shapes, or generated request examples. For a guided integration with SDK `0.18.0`, start with the [Quickstart](/en/quickstart) or [API Guides](/en/api-guides).
## Choose by input lifecycle
| Workflow | Input state | Best fit |
| --- | --- | --- |
| Batch transcription | One complete, long-form recording | Meetings, podcasts, interviews, and archives processed as asynchronous jobs |
| Fast transcription | One complete, bounded audio unit | Latency-sensitive agent turns, voice commands, and short conversational utterances |
| Realtime ASR | Audio is still arriving | Live microphones, calls, and other streams that need partial and final results |
| Text to speech | Text input; audio output | Generate a PCM16 audio stream from text |
## Configure access
Obtain an API key through your organization’s approved access flow. Keep the key on a trusted backend and use the host and route path configured for your environment. See [Authentication](/en/authentication) before exposing an integration to users.
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
| API | Base path |
| --- | --- |
| Batch API | `/v1` |
| Realtime HTTP API | `/realtime` |
## Send a safe request
A read-only lookup for a deliberately unknown job ID provides non-mutating diagnostic evidence without creating work:
```bash
curl --include "$API_URL/v1/transcribe/00000000-0000-4000-8000-000000000000" \
--header "x-api-key: $API_KEY" \
--header "Origin: $API_URL"
```
- `404` is compatible with lookup of the unknown job, but does not by itself prove that the credential and Batch capability are valid.
- `401` indicates that the key is missing or invalid for the request path.
- `403` indicates that access was denied; verify the configured values through your organization’s approved access flow.
## Reference sections
### [Batch API](/en/api-reference/batch)
Submit complete long-form recordings, then poll a job to a terminal state.
### [Realtime HTTP API](/en/api-reference/realtime-http)
Stream Fast, live ASR, diarization, or text-to-speech over HTTP.
## Operational boundaries
- A Batch submit can return `429` when audio-processing capacity is exhausted. Treat the response as backpressure and use the returned capacity data when it is present.
- Do not blindly retry an ambiguous file upload. Record the request outcome in your job layer so a timeout cannot create duplicate work unnoticed.
- Use bounded polling for Batch jobs and stop on `done`, `failed`, or `cleared`.
- The HTTP and Socket.IO realtime surfaces have different framing and lifecycle rules. Follow the page for the transport you actually use.
## Markdown and LLM access
- Use [`/en/api-reference/md`](/en/api-reference/md) for this page as raw Markdown.
- Append an operation slug, such as [`/en/api-reference/md/batch/submit-transcription-job`](/en/api-reference/md/batch/submit-transcription-job), for one operation.
- Use [`/llms-full.txt`](/llms-full.txt) for the complete bilingual documentation bundle.
## Next steps
### [Authentication](/en/authentication)
Obtain, configure, and protect an API key.
### [API Guides](/en/api-guides)
Choose a protocol and follow its lifecycle.
### [Errors and rate limits](/en/api-guides/errors-and-rate-limits)
Classify failures and implement safe retries.
---
# Get transcription job status or result (V1 legacy)
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/batch/get-transcription-job-legacy
## Operation
**GET `/transcribe/{job_id}/{lang}`**
- **Base URL:** `https://api.voice.humain.com/v1`
- **Request URL:** `https://api.voice.humain.com/v1/transcribe/{job_id}/{lang}`
## Description
Legacy compatibility operation used by JavaScript and Python SDK
`0.18.0`. New direct HTTP integrations should use
`GET /transcribe/{job_id}` (V2).
Use the `jobId` returned by submission. Poll `status` with a timeout on
each request and one finite application deadline. Continue only for
`queued` and `processing`; stop on `done`, `failed`, or `cleared`. Read
`results.transcript` and `results.offsets` only for `done`. A `failed`
V1 response does not include a machine-readable failure reason;
`cleared` means stored result fields are unavailable. All five job
statuses use HTTP `200`; non-2xx responses are request, authentication,
authorization, lookup, or server errors.
With the default `save_result=false`, a `done` or `failed` delivery can
be single-consumption. Set `save_result=true` on every poll when a lost
terminal response must be fetched again. The API defines no retention
duration.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `x-api-key`
## Parameters
### Parameter `job_id`
- **Location:** `path`
- **Required:** yes
- **Type:** `string (uuid)`
Transcription job ID.
**Schema:**
```yaml
type: string
format: uuid
```
**Examples:**
None documented.
### Parameter `lang`
- **Location:** `path`
- **Required:** yes
- **Type:** `string`
Legacy compatibility segment required by the route. The current V1
handler does not use or validate this value. SDK `0.18.0` sends the
language used at submission. New direct HTTP clients should use
`GET /transcribe/{job_id}`.
**Schema:**
```yaml
type: string
minLength: 1
examples:
- en
```
**Examples:**
```yaml
- en
```
### Parameter `save_result`
- **Location:** `query`
- **Required:** no
- **Type:** `boolean`
Leave stored terminal result fields available after this fetch. The
default `false` can make a `done` or `failed` delivery
single-consumption. Set `true` on every poll when terminal delivery
must be retried. This option defines no retention duration.
**Schema:**
```yaml
type: boolean
default: false
```
**Examples:**
```yaml
default:
value: true
```
### Parameter `diarization_force_align`
- **Location:** `query`
- **Required:** no
- **Type:** `boolean`
Controls only `results.offsets[].speaker`; `diarization_segments` is
unchanged. With `true` (default), a word whose `startTime` is outside
every real segment uses the speaker from the nearest segment
boundary, measured from the word midpoint; ties use the earlier
segment. With `false`, such words use `UNKNOWN_SPEAKER`. With no real
segments, `speaker` remains `null`. SDK `0.18.0` does not expose this
option. Accepted values are true/false or 1/0.
**Schema:**
```yaml
type: boolean
default: true
```
**Examples:**
None documented.
## Request body
None documented.
## Responses
### Response `200`
Legacy transcription response
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- status
- APIVersion
- version
- metadata
- results
- diarization_segments
properties:
status:
type: string
enum:
- queued
- processing
- done
- failed
- cleared
description: |
Job status:
- `queued`: Job is waiting to be processed
- `processing`: Job is currently being transcribed
- `done`: Transcription completed successfully
- `failed`: Transcription failed
- `cleared`: Stored result fields are unavailable; stop polling. This
status defines no media-deletion or retention guarantee
APIVersion:
type: string
enum:
- v1
examples:
- v1
version:
type: string
enum:
- api-version
examples:
- api-version
metadata:
type: object
required:
- sautechVersion
- jobId
- fileDuration
properties:
sautechVersion:
type: string
enum:
- v1
examples:
- v1
jobId:
type: string
format: uuid
fileDuration:
type: number
format: float
results:
type: object
required:
- transcript
properties:
transcript:
type: string
offsets:
type: array
items:
type: object
required:
- word
- startTime
- endTime
properties:
word:
type: string
startTime:
type: number
format: float
endTime:
type: number
format: float
speaker:
type:
- string
- "null"
diarization_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
speaker:
type:
- string
- "null"
```
**Examples:**
```yaml
queued:
summary: Job is queued
value:
status: queued
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: null
processing:
summary: Job is processing
value:
status: processing
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: null
done:
summary: Job is complete
value:
status: done
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: hello world
offsets:
- word: hello
startTime: 0
endTime: 0.45
speaker: speaker-1
- word: world
startTime: 0.46
endTime: 0.9
speaker: null
diarization_segments:
- start_time: 0
end_time: 1
speaker: speaker-1
failed:
summary: Job failed
value:
status: failed
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: null
cleared:
summary: Stored result fields are unavailable
value:
status: cleared
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: []
```
### Response `400`
Invalid job ID, `save_result`, or `diarization_force_align` value
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
invalid_job_id:
summary: Invalid job ID
value:
error: error.uuid.invalid
code: VALIDATION_INVALID_UUID
detail: error.uuid.invalid
job_id: not-a-uuid
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_save_result:
summary: Invalid save_result value
value:
error: error.api.error.param.save_result.invalid
code: VALIDATION_INVALID_PARAM
detail: error.api.error.param.save_result.invalid
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_force_align:
summary: Invalid diarization_force_align value
value:
error: error.api.error.param.diarization_force_align.invalid
code: VALIDATION_INVALID_PARAM
detail: error.api.error.param.diarization_force_align.invalid
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
missing_key:
value:
error: auth.unauthorized
message: unauthorized
code: AUTH_UNAUTHORIZED
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant batch transcription access
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
scope_denied:
value:
error: error.api_key.scope_denied
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `404`
Transcription job not found
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
missing_job:
value:
error: error.transcription_job.get
code: TRANSCRIPTION_JOB_NOT_FOUND
detail: transcription job not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `500`
Legacy result lookup or post-response result clearing failed
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
lookup_failed:
value:
error: error.transcription_job.get
code: SERVER_INTERNAL
detail: error.transcription_job.get
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
clear_failed:
value:
error: error.transcription_job.clear_result_failed
code: SERVER_INTERNAL
detail: error.transcription_job.clear_result_failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
invalid_save_result:
summary: Invalid save_result value
value:
error: error.api.error.param.save_result.invalid
code: VALIDATION_INVALID_PARAM
detail: error.api.error.param.save_result.invalid
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
Keep V1 only where SDK `0.18.0` compatibility requires it. For a new direct HTTP client, move to V2; in either case, stop polling on `done`, `failed`, or `cleared`.
### [Move direct HTTP to V2](/en/api-reference/batch/get-transcription-job)
Use the recommended status and result contract for new HTTP integrations.
### [Use the released SDK safely](/en/recipes/transcribe-a-recording)
Follow the tested `0.18.0` recipe that still consumes the V1 shape.
### [Bound retries and polling](/en/api-guides/errors-and-rate-limits)
Separate terminal job states from transport and API failures.
---
# Get transcription job status or result (V2)
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/batch/get-transcription-job
## Operation
**GET `/transcribe/{job_id}`**
- **Base URL:** `https://api.voice.humain.com/v1`
- **Request URL:** `https://api.voice.humain.com/v1/transcribe/{job_id}`
## Description
Recommended status and result operation for new direct HTTP integrations.
Use the `jobId` returned by `POST /transcribe/{lang}` as `job_id`, call
this operation from a trusted backend, and send `x-api-key`.
A successful read returns `{ "message": "success", "data": ... }`. Poll
`data.status` with a timeout on every request and one finite application
deadline. Continue only for `queued` and `processing`; stop on `done`,
`failed`, or `cleared`. Consume `data.final_result` and related result
fields only when status is `done`. `cleared` is terminal and means the
result is unavailable.
This V2 response is intended for direct HTTP integrations. JavaScript
and Python SDK `0.18.0` use the legacy V1 route and response shape.
With `save_result=false` (the default), a successful read of a `done` or
`failed` job can clear stored result fields after constructing the
response. A later read can therefore return `cleared`. Set
`save_result=true` when terminal retrieval must be repeatable. The API
does not define a retention duration.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `x-api-key`
## Parameters
### Parameter `job_id`
- **Location:** `path`
- **Required:** yes
- **Type:** `string (uuid)`
Transcription job ID.
**Schema:**
```yaml
type: string
format: uuid
```
**Examples:**
None documented.
### Parameter `save_result`
- **Location:** `query`
- **Required:** no
- **Type:** `boolean`
Preserve terminal result fields after this fetch. The default is
`false`. With `false`, a `done` or `failed` read can clear stored
result fields after returning them, and a later read can return
`cleared`. Set `true` before polling when the application must retry
or fetch the terminal result again. This option does not define a
retention duration.
**Schema:**
```yaml
type: boolean
default: false
```
**Examples:**
None documented.
## Request body
None documented.
## Responses
### Response `200`
Transcription job
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- message
- data
properties:
message:
type: string
enum:
- success
examples:
- success
data:
type: object
required:
- id
- version
- created_at
- updated_at
- language
- audio_duration
- sample_rate_hz
- status
properties:
id:
type: string
format: uuid
version:
type: integer
format: int32
created_at:
type:
- string
- "null"
format: date-time
updated_at:
type:
- string
- "null"
format: date-time
language:
type: string
enum:
- en
- ar
- codeswitch
- auto
audio_duration:
type: number
format: float
sample_rate_hz:
type: integer
format: int32
description: Processed audio sample rate in hertz.
examples:
- 16000
status:
type: string
enum:
- queued
- processing
- done
- failed
- cleared
description: |
Job status:
- `queued`: Job is waiting to be processed
- `processing`: Job is currently being transcribed
- `done`: Transcription completed successfully
- `failed`: Transcription failed
- `cleared`: Stored result fields are unavailable; stop polling. This
status defines no media-deletion or retention guarantee
asr_result:
type:
- string
- "null"
asr_word_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
diarization_segments:
type:
- array
- "null"
description: Speaker time ranges returned separately from word timings.
items:
type: object
required:
- start_time
- end_time
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
speaker:
type:
- string
- "null"
itn_result:
type:
- string
- "null"
itn_word_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
itn_output_formats:
type:
- string
- "null"
redaction_result:
type:
- string
- "null"
redaction_word_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
redaction_labels:
type:
- string
- "null"
final_result:
type:
- string
- "null"
description: Final transcript available when `status` is `done`.
final_word_segments:
type:
- array
- "null"
description: Final word timings. Speaker labels are not included on these objects.
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
```
**Examples:**
```yaml
queued:
summary: Job is queued
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:00.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: queued
processing:
summary: Job is processing
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:02.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: processing
done:
summary: Job is complete
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:05.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: done
asr_result: hello world
asr_word_segments:
- start_time: 0
end_time: 0.45
word: hello
diarization_segments:
- start_time: 0
end_time: 1
speaker: speaker-1
itn_result: null
itn_word_segments: null
itn_output_formats: null
redaction_result: null
redaction_word_segments: null
redaction_labels: ""
final_result: hello world
final_word_segments:
- start_time: 0
end_time: 0.45
word: hello
failed:
summary: Job failed
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:05.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: failed
cleared:
summary: Stored result was cleared
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:06.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: cleared
```
### Response `400`
Invalid job ID or `save_result` value
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
invalid_job_id:
summary: Invalid job ID
value:
error: error.uuid.invalid
code: VALIDATION_INVALID_UUID
detail: error.uuid.invalid
job_id: not-a-uuid
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
missing_key:
value:
error: auth.unauthorized
message: unauthorized
code: AUTH_UNAUTHORIZED
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant batch transcription access
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
scope_denied:
value:
error: error.api_key.scope_denied
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `404`
Transcription job not found
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
missing_job:
value:
error: error.transcription_job.get
code: TRANSCRIPTION_JOB_NOT_FOUND
detail: transcription job not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `500`
Internal server error
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
internal:
value:
error: error.transcription_job.get
code: SERVER_INTERNAL
detail: error.transcription_job.get
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
Turn this lookup into a bounded poller: continue only for `queued` and `processing`, stop for every terminal state, and set `save_result=true` whenever a lost terminal response must be retrievable again.
### [Implement bounded polling](/en/api-guides/batch-rest)
Add request timeouts, an overall deadline, and complete terminal-state handling.
### [Run the SDK workflow](/en/recipes/transcribe-a-recording)
Use the tested JavaScript or Python SDK `0.18.0` recording recipe.
### [Handle lookup failures](/en/api-guides/errors-and-rate-limits)
Classify authentication, not-found, rate-limit, and server responses.
---
# Batch API
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/batch
Choose Batch when the entire recording already exists and the workload is long-form: meetings, podcasts, interviews, calls, or archives. Upload the file once, persist the returned job ID, and retrieve the result asynchronously.
> **Direct HTTP V2 and SDK 0.18.0**
>
> For a new direct HTTP integration, prefer `GET /v1/transcribe/{job_id}` and its V2 response. The JavaScript and Python SDKs at `0.18.0` currently poll the legacy V1 route, so keep that response shape when you use the released SDK helpers.
## Job lifecycle
1. Submit one complete audio file and record the returned `jobId` before doing other work.
2. Before polling, set `save_result=true` when a lost terminal response must be retrievable again; then use a bounded interval, an overall deadline, and jitter where workers share capacity.
3. Continue while the status is `queued` or `processing`.
4. Stop on every terminal status: consume `done`, surface `failed`, and treat `cleared` as unavailable output.
## Endpoints
### [POST · Submit a transcription job](/en/api-reference/batch/submit-transcription-job)
Upload audio, choose language and processing options, and receive a job ID.
### [GET · Get a job (V2)](/en/api-reference/batch/get-transcription-job)
Recommended direct HTTP lookup with the standard success wrapper.
### [GET · Get a job (V1 legacy)](/en/api-reference/batch/get-transcription-job-legacy)
Legacy response used by the JavaScript and Python SDK `0.18.0` helpers.
## Handle every terminal state
| Status | Meaning | Client action |
| --- | --- | --- |
| `queued` | Waiting for processing | Keep polling within your deadline |
| `processing` | Transcription is running | Keep polling within your deadline |
| `done` | Output is ready | Validate and store the result you need |
| `failed` | Processing failed | Stop polling and surface the failure |
| `cleared` | Stored output was cleared | Stop polling; do not wait for a later result |
## Production notes
- A submit can return `429` with remaining audio capacity in seconds. Back off and bound retries instead of immediately resubmitting.
- A timeout after upload is ambiguous: the service may have accepted the file even when the client did not receive the response. Track attempts and reconcile before retrying.
- Set both a per-request timeout and an overall polling deadline. Neither the API nor a helper loop should be allowed to wait forever.
- The default `save_result=false` can clear stored fields after constructing a `done` or `failed` response. Use `true` for repeatable delivery, but do not infer a retention duration.
- Use Fast for one bounded conversational utterance that is already complete. Keep long recordings on Batch.
## Next steps
### [Batch REST guide](/en/api-guides/batch-rest)
Build the complete direct HTTP lifecycle.
### [Transcribe a recording](/en/recipes/transcribe-a-recording)
Run a tested SDK `0.18.0` example.
### [Errors and rate limits](/en/api-guides/errors-and-rate-limits)
Make polling and retries safe.
---
# Submit a transcription job
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/batch/submit-transcription-job
## Operation
**POST `/transcribe/{lang}`**
- **Base URL:** `https://api.voice.humain.com/v1`
- **Request URL:** `https://api.voice.humain.com/v1/transcribe/{lang}`
## Description
Submit one complete recording for asynchronous Batch transcription. Use
Batch for long or large complete media; use Fast for one complete,
bounded, latency-sensitive conversational unit, and Realtime only while
audio is still arriving.
A `200` response means the job was accepted with status `queued`, not
that transcription finished. Persist `jobId`, then poll
`GET /transcribe/{job_id}` until `done`, `failed`, or `cleared`.
This operation has no idempotency-key contract. Do not blindly replay an
upload after a timeout, connection loss, or `5xx`: the job may already
exist and a replay can create duplicate work. A `429` response is
capacity backpressure; `data.capacity` is remaining audio capacity in
seconds when a balance is available, not a delay or reset time.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `x-api-key`
## Parameters
### Parameter `lang`
- **Location:** `path`
- **Required:** yes
- **Type:** `string`
Language code for transcription.
**Schema:**
```yaml
type: string
enum:
- en
- ar
- codeswitch
- auto
```
**Examples:**
None documented.
### Parameter `asr`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Optional exact ASR model key. When omitted, the service uses the
configured default for the selected `lang`. An unknown key or a
missing configured default returns `400` with `ASR_MODEL_NOT_FOUND`.
**Schema:**
```yaml
type: string
```
**Examples:**
None documented.
### Parameter `diarization`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Speaker diarization selector:
- omitted, `0`, or `false`: Disabled
- `1` or `true`: Enabled with default model
- `d1`: Speaker diarization
- `d2`: Speaker diarization (alternative)
**Schema:**
```yaml
type: string
enum:
- "0"
- "1"
- "false"
- "true"
- d1
- d2
```
**Examples:**
```yaml
enable:
value: "1"
disable:
value: "0"
enable_boolean:
value: "true"
disable_boolean:
value: "false"
d1:
value: d1
d2:
value: d2
```
### Parameter `itn`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Inverse Text Normalization (ITN) selector:
- omitted, `0`, or `false`: Disabled
- `1` or `true`: Enabled (converts spoken forms to written, e.g., "twenty five" → "25")
**Schema:**
```yaml
type: string
enum:
- "0"
- "1"
- "false"
- "true"
```
**Examples:**
```yaml
enable:
value: "1"
disable:
value: "0"
enable_boolean:
value: "true"
disable_boolean:
value: "false"
```
### Parameter `redact`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
PII Redaction selector:
- omitted, `0`, or `false`: Disabled
- `1` or `true`: Enabled (masks sensitive information in transcripts)
**Schema:**
```yaml
type: string
enum:
- "0"
- "1"
- "false"
- "true"
```
**Examples:**
```yaml
enable:
value: "1"
disable:
value: "0"
enable_boolean:
value: "true"
disable_boolean:
value: "false"
```
## Request body
- **Required:** yes
#### Content type: `multipart/form-data`
**Schema:**
```yaml
type: object
required:
- file
properties:
file:
type: string
description: |
One complete audio recording, and the only audio part accepted.
Unsupported, corrupt, empty, or zero-duration input returns `422`.
A recording longer than the decoded-duration limit returns `422`
`AUDIO_DURATION_EXCEEDED`; a second audio part returns `422`
`FILE_COUNT_EXCEEDED`. See "Request limits".
contentMediaType: application/octet-stream
```
**Examples:**
None documented.
## Responses
### Response `200`
Job accepted and queued for asynchronous processing
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- jobId
- status
properties:
jobId:
type: string
format: uuid
status:
type: string
enum:
- queued
examples:
- queued
```
**Examples:**
```yaml
queued:
value:
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
status: queued
```
### Response `400`
Invalid language, model, content type, multipart body, or file field
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
invalid_language:
summary: Invalid language
value:
error: error.language.invalid
code: VALIDATION_INVALID_LANGUAGE
detail: error.language.invalid
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_content_type:
summary: Request is not multipart form data
value:
error: error.api.error.request.invalid_format
code: VALIDATION_INVALID_FORMAT
detail: error.api.error.request.invalid_format
retryable: false
timestamp: 2026-01-15T10:30:00Z
missing_file:
summary: First multipart field is not file
value:
error: error.api.error.multipart.file.missing
code: VALIDATION_REQUIRED_FIELD
detail: error.api.error.multipart.file.missing
retryable: false
timestamp: 2026-01-15T10:30:00Z
unknown_asr_model:
summary: ASR model is not configured
value:
error: error.asr_model.not_found
code: ASR_MODEL_NOT_FOUND
detail: error.asr_model.not_found
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
missing_key:
value:
error: auth.unauthorized
message: unauthorized
code: AUTH_UNAUTHORIZED
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant batch transcription access
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
scope_denied:
value:
error: error.api_key.scope_denied
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `413`
The request exceeded the byte limit. No job was created and no transcription was
started. `data.observed` is the client's declared
`Content-Length` when it already exceeded the limit; when the body was rejected
while being read it is `limit + 1`, the smallest provable size, because reading
stops there.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
declared_too_large:
summary: Content-Length already exceeds the limit
value:
error: error.api.error.request.too_large
code: PAYLOAD_TOO_LARGE
detail: error.api.error.request.too_large
retryable: false
timestamp: 2026-01-15T10:30:00Z
request_id: 4bf92f3577b34da6a3ce929d0e0e4736
data:
limit: 536870912
observed: 1073741824
unit: bytes
bound: request_bytes
unvalidatable_tail:
summary: Too much data beyond the recording to finish checking the limits
value:
error: error.api.error.request.unvalidatable_tail
code: PAYLOAD_TOO_LARGE
detail: error.api.error.request.unvalidatable_tail
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 524288
observed: 524289
unit: bytes
bound: unvalidatable_tail_bytes
overran_while_reading:
summary: Body overran the limit mid-stream
value:
error: error.api.error.request.too_large
code: PAYLOAD_TOO_LARGE
detail: error.api.error.request.too_large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 536870912
observed: 536870913
unit: bytes
bound: request_bytes
```
### Response `422`
Unsupported or corrupt audio input, or a valid request whose workload exceeds a
semantic limit. No job was created and no transcription was started; see
"Request limits" for when audio is converted before the rejection.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
unsupported_audio:
value:
error: unsupported or corrupt audio input for conversion
code: VALIDATION_FILE_CORRUPT
detail: unsupported or corrupt audio input for conversion
retryable: false
timestamp: 2026-01-15T10:30:00Z
audio_too_long:
summary: Decoded audio exceeds the duration limit
value:
error: error.api.error.audio.duration_exceeded
code: AUDIO_DURATION_EXCEEDED
detail: error.api.error.audio.duration_exceeded
retryable: false
timestamp: 2026-01-15T10:30:00Z
request_id: 4bf92f3577b34da6a3ce929d0e0e4736
data:
limit: 14400
observed: 21600
unit: seconds
bound: audio_duration
too_many_files:
summary: More than one audio part was submitted
value:
error: error.api.error.multipart.file.count_exceeded
code: FILE_COUNT_EXCEEDED
detail: error.api.error.multipart.file.count_exceeded
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1
observed: 2
unit: files
bound: file_parts
too_many_parts:
summary: More multipart parts than the request allows
value:
error: error.api.error.multipart.part.count_exceeded
code: FILE_COUNT_EXCEEDED
detail: error.api.error.multipart.part.count_exceeded
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 8
observed: 9
unit: parts
bound: multipart_parts
```
### Response `429`
Audio capacity is exhausted. `data.capacity` is remaining audio seconds
when a balance is available; it is not a retry delay, reset timestamp,
or quota guarantee. A zero value can mean no balance was available.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
- data
properties:
error:
type: string
code:
type: string
enum:
- RATE_LIMIT_EXCEEDED
detail:
type: string
retryable:
type: boolean
timestamp:
type: string
format: date-time
data:
type: object
required:
- capacity
properties:
capacity:
type: number
format: float
description: |
Remaining audio-processing capacity in seconds when a balance
is available. This is not a retry delay or reset timestamp; zero
can mean no balance was available.
```
**Examples:**
```yaml
limited:
value:
error: error.rate_limit
code: RATE_LIMIT_EXCEEDED
detail: error.rate_limit
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
capacity: 120.5
```
### Response `500`
Submission failed; the outcome can be ambiguous after job creation
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set this
service emits in an `ErrorResponse` body. The `429` rate-limit
response uses `RateLimitErrorResponse` and carries
`RATE_LIMIT_EXCEEDED` instead.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
description: |
Job identifier supplied by the client. It can be a valid UUID for
post-creation errors or the invalid submitted value when `code` is
`VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
request_id:
type: string
description: |
Trace identifier for this request, for correlation in a support request.
Present on request-limit rejections; absent when tracing is not recording.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: The limit that was exceeded, its configured value and what was observed.
properties:
limit:
type: integer
format: int64
description: The configured maximum, in `unit`.
observed:
type: integer
format: int64
description: |
The observed value, in `unit`. Always greater than `limit`. Durations are
rounded up, so a recording a fraction of a second over the ceiling still
reports a value above it.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: Which limit was exceeded.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |
Present only on a request-limit rejection (`PAYLOAD_TOO_LARGE`,
`AUDIO_DURATION_EXCEEDED`, `FILE_COUNT_EXCEEDED`). Absent otherwise.
```
**Examples:**
```yaml
transcription_failed:
value:
error: error.api.transcription
code: ASR_TRANSCRIPTION_FAILED
detail: error.api.transcription
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
Once the request returns a `jobId`, persist it before leaving your request handler. Then poll the V2 lookup with a bounded deadline until the job reaches `done`, `failed`, or `cleared`.
### [Poll the job with V2](/en/api-reference/batch/get-transcription-job)
Read the recommended direct HTTP status and result shape.
### [Build the Batch lifecycle](/en/api-guides/batch-rest)
Connect submission, bounded polling, and terminal-state handling.
### [Plan safe failure handling](/en/api-guides/errors-and-rate-limits)
Handle capacity pressure and ambiguous upload outcomes without blind retries.
---
# Stream fast transcription for one complete audio unit
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/realtime-http/fast-transcription
## Operation
**POST `/http/stt`**
- **Base URL:** `https://api.voice.humain.com/realtime`
- **Request URL:** `https://api.voice.humain.com/realtime/http/stt`
## Description
Transcribe one complete, bounded, latency-sensitive audio unit, such as
one finished user turn in an agentic conversation or a voice command.
Use Batch for long or large complete recordings, and Realtime ASR while
audio is still arriving.
This is a direct HTTP operation. SDK `0.18.0` Fast clients use Socket.IO;
they do not call this route. Send the request from a trusted backend with
`X-Api-Key` and the realtime ASR capability.
Supply a unique UUID in `id` and one complete audio file in the multipart
field `file`. A nonempty `language` takes precedence over `lang`; a
nonempty `asr` takes precedence over `model`. Omitted or `auto` language
and an omitted model use defaults configured for the environment. Fast
applies only language and ASR model selection; use Batch when
diarization, ITN, or redaction is required.
The response is NDJSON. A request can emit partial transcription records
before the final record. If a later callback fails after output was
flushed, the partial `200` stream ends without an appended JSON error.
Require exactly observed `is_final: true` for completion, and treat EOF,
cancellation, or an application deadline without a final record as
incomplete. `seq` is opaque diagnostic data and has no ordering or
uniqueness guarantee.
## Limits
Two independent bounds apply, and they measure different things.
The whole multipart request body must not exceed **64 MiB**
(`67108864` bytes). Exceeding it is `413` with code `PAYLOAD_TOO_LARGE`
and `data.bound: fast_audio_bytes`.
The audio must not DECODE to more than **1800 seconds** (30 minutes).
Exceeding it is `422` with code `AUDIO_DURATION_EXCEEDED` and
`data.bound: fast_audio_duration`. This is a separate bound because a
small compressed upload can decode to many hours: a request that is
perfectly acceptable in bytes can still ask for more audio work than
this endpoint performs. Both bounds are inclusive - exactly at the limit
succeeds, and only strictly over it fails.
The service enforces the duration bound from the container header where
the file declares its own length, from container metadata where the
decoder can read it, and otherwise while decoding, stopping at the
ceiling. Over-long audio is therefore refused before any inference, and
consumes no audio-capacity credit. Deployments can override both bounds
with `REALTIME_MAX_BODY_BYTES_FAST_TRANSCRIPTION` and
`REALTIME_MAX_FAST_AUDIO_DURATION_SEC`, so this schema does not declare
a fixed `maxLength`.
For recordings longer than 30 minutes, or larger than 64 MiB, split the
audio into shorter units or use the batch transcription API, whose
ceiling is 4 hours per file.
## Audio format
The payload must be AAC (ADTS), FLAC, MP3, WAV, or an ISO base media
file. The container is identified by the server from the payload itself,
never from a filename or a media type, and anything else is rejected with
`400` and code `ASR_UNSUPPORTED_CODEC` even when it is otherwise
decodable.
The ISO base media entry is a family: MP4 is the intended and supported
form, and MOV, M4A, 3GP, 3G2 and MJ2 share one demuxer with it and are
therefore admitted by the same check. Only MP4 is tested and intended; do
not build on the others. Put the `moov` atom at the FRONT of the file -
not a policy the server rejects on, but a practical requirement, because
the upload is read forward-only and a trailing `moov` cannot be reached.
Sample rate and channel count are not restricted: audio is resampled and
downmixed to mono at the sample rate configured for the selected ASR
model, which the client does not choose.
Apply finite connect, inactivity, and overall deadlines. This operation
has no idempotency or replay contract; do not blindly resubmit after an
ambiguous timeout or disconnect.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `X-Api-Key`
## Parameters
### Parameter `id`
- **Location:** `query`
- **Required:** yes
- **Type:** `string (uuid)`
Fresh client-generated correlation UUID. It is not an idempotency key.
**Schema:**
```yaml
type: string
format: uuid
```
**Examples:**
None documented.
### Parameter `language`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Language for transcription. Alias `lang` is also accepted.
A nonempty `language` takes precedence over `lang`. Blank or `auto`
resolves to the default configured for the environment, currently
the code-switching model.
**Schema:**
```yaml
type: string
enum:
- en
- ar
- codeswitch
- auto
```
**Examples:**
None documented.
### Parameter `asr`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Optional exact ASR model key; `model` is also accepted as an alias.
A nonempty `asr` takes precedence. If both are omitted, the service
uses the configured default for the selected language.
**Schema:**
```yaml
type: string
```
**Examples:**
None documented.
### Parameter `model`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Alias for `asr`.
**Schema:**
```yaml
type: string
```
**Examples:**
None documented.
### Parameter `lang`
- **Location:** `query`
- **Required:** no
- **Type:** `string`
Alias used only when `language` is omitted or empty.
**Schema:**
```yaml
type: string
enum:
- en
- ar
- codeswitch
- auto
```
**Examples:**
None documented.
## Request body
- **Required:** yes
#### Content type: `multipart/form-data`
**Schema:**
```yaml
type: object
required:
- file
properties:
file:
type: string
description: One complete, bounded audio unit. Fast decodes the uploaded file before ASR.
contentMediaType: application/octet-stream
```
**Examples:**
None documented.
## Responses
### Response `200`
Zero or more transcription NDJSON records. Once output has started,
a later failure ends the partial stream without an appended JSON
error. Completion requires an observed record with `is_final: true`.
**Headers:**
```yaml
Cache-Control:
schema:
type: string
enum:
- no-store
description: Prevents intermediaries from caching transcript records.
```
#### Content type: `application/x-ndjson`
**Schema:**
```yaml
type: object
required:
- id
- seq
- transcription
- words
- is_final
properties:
id:
type: string
format: uuid
description: Transcription request identifier.
seq:
type: integer
format: int64
description: Opaque diagnostic value with no ordering or uniqueness guarantee.
transcription:
type: string
description: Transcribed text chunk.
words:
type: array
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
description: Word text.
is_final:
type: boolean
description: True for final chunk.
```
**Examples:**
```yaml
partial:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello wor
words:
- start_time: 0
end_time: 0.45
word: hello
is_final: false
final:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello world
words:
- start_time: 0
end_time: 0.45
word: hello
- start_time: 0.46
end_time: 0.9
word: world
is_final: true
```
### Response `400`
Invalid request ID, language, multipart upload, audio container, or ASR
model. Every case here is client-fixable, so none of them is ever
reported as a `5xx`.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
invalid_id:
summary: Invalid request ID
value:
error: invalid request id
code: VALIDATION_INVALID_UUID
detail: invalid request id
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_language:
summary: Invalid language
value:
error: invalid language
code: VALIDATION_INVALID_LANGUAGE
detail: invalid language
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_file:
summary: Invalid multipart file upload
value:
error: invalid file upload
code: VALIDATION_FILE_CORRUPT
detail: invalid file upload
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
unsupported_container:
summary: Audio container is outside the published set
description: |
The payload must be AAC (ADTS), FLAC, MP3, WAV, or an ISO base
media file. A container the decoder could otherwise read is still
refused, so this is a contract decision rather than a decode
failure. Re-encode and resubmit; the identical bytes cannot
succeed. See "Audio format" on the operation for the exact
accepted set and for why `moov` placement is a practical
requirement rather than something the server rejects on.
value:
error: audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV
code: ASR_UNSUPPORTED_CODEC
detail: audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
unknown_model:
summary: ASR model is not configured
value:
error: ASR model not found
code: ASR_MODEL_NOT_FOUND
detail: ASR model not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant access to the requested voice capability
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `405`
Method not allowed
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `413`
The request body exceeded the configured byte limit for this audio route:
64 MiB for Fast uploads, 16 MiB for Realtime ASR frames, 16 MiB for
Realtime diarization frames. Non-retryable at the same size; resend a
smaller unit or chunk.
`data.bound` names which byte limit was hit - `fast_audio_bytes`,
`realtime_asr_frame_bytes`, or `realtime_diarization_frame_bytes`.
`data.observed` is the exact request size when the client declared a
`Content-Length`, and otherwise a MINIMUM (the limit plus one byte),
because a body with no declared length is cut off mid-read and its true
size is never learned.
This status is only ever reached from a BYTE count. A request whose bytes
are acceptable but whose decoded audio is too long is `422` with
`AUDIO_DURATION_EXCEEDED` instead.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
declared_length_over_the_cap:
summary: Content-Length was declared, so observed is exact
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 20971520
unit: bytes
bound: realtime_asr_frame_bytes
streamed_body_over_the_cap:
summary: No declared length, so observed is the limit plus one byte
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 67108864
observed: 67108865
unit: bytes
bound: fast_audio_bytes
```
### Response `422`
The request parsed correctly and its bytes were acceptable, but the
amount of AUDIO it asks the service to process exceeds this endpoint's
ceiling (RFC 9110 15.5.21). A small compressed upload that decodes to
many hours is exactly this case, which is why it is not `413`.
`data.bound` names which audio ceiling was hit:
* `fast_audio_duration` - one Fast submission decoded to more than 1800
seconds. Split the recording or use the batch transcription API.
* `session_audio_duration` - a realtime session has now sent more total
audio content than its 14400-second (4 hour) allowance. The session is
retired; start a new one.
`data.observed` is in whole seconds, rounded up. Where the service
stopped decoding at the ceiling it never learned the true total length,
so the observed value is a MINIMUM rather than an exact measurement.
Not retryable: resending the identical audio cannot succeed. Shorten the
unit, or move to the batch API.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
fast_decoded_audio_too_long:
value:
error: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
code: AUDIO_DURATION_EXCEEDED
detail: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1800
observed: 3601
unit: seconds
bound: fast_audio_duration
session_audio_allowance_spent:
value:
error: session maximum audio duration exceeded; start a new session
code: AUDIO_DURATION_EXCEEDED
detail: session maximum audio duration exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 14400
observed: 14401
unit: seconds
bound: session_audio_duration
```
### Response `429`
Gateway rate limiting. Response details and retry headers are deployment-specific.
None documented.
### Response `500`
Fast transcription failed before a final record was emitted
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
transcription_failed:
value:
error: STT transcription failed
code: ASR_TRANSCRIPTION_FAILED
detail: STT transcription failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
Use Fast only after one bounded conversational audio unit is complete. Parse every NDJSON record, commit output only from a final record, and keep long recordings such as podcasts and meetings on Batch.
### [Implement the HTTP stream](/en/api-guides/realtime-http)
Handle multipart input, NDJSON records, finality, deadlines, and cleanup.
### [Compare the SDK transport](/en/api-guides/socketio)
Use Socket.IO when the released JavaScript or Python SDK fits your runtime.
### [Handle stream failures](/en/api-guides/errors-and-rate-limits)
Recognize structured stream errors and gateway-level HTTP failures.
---
# Realtime HTTP API
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/realtime-http
Use these endpoints when HTTP streaming fits your runtime better than Socket.IO. Choose the endpoint from the state of the input—not only from the latency you want.
> **Direct HTTP only**
>
> JavaScript and Python SDK `0.18.0` use Socket.IO and default to `/socket.io`; they do not call these routes. Use this section when implementing an HTTP client directly.
## Choose an endpoint
| Endpoint | Input contract | Choose it for |
| --- | --- | --- |
| Fast · `/http/stt` | One complete, bounded audio unit | A finished agent turn, voice command, or short conversational utterance |
| Realtime ASR · `/http/stt-stream` | One framed chunk from audio that is still arriving | Live transcription with partial and final ASR updates |
| Realtime diarization · `/http/diarization-stream` | One framed chunk from audio that is still arriving | Incremental speaker segments for a live stream |
| TTS · `/http/tts` | One JSON request; undelimited binary capture | Inspect the direct protocol; use SDK TTS for playable audio |
> **Fast is not the long-recording path**
>
> Fast is optimized for a complete but bounded, latency-sensitive unit such as one turn in an agentic conversation. Use Batch for large files, podcasts, long meetings, and archive processing.
## Connection and authentication
Build requests from the provisioned `API_URL` plus the `/realtime` base path. Send `x-api-key` from a trusted backend. The key also needs the provisioned capability: realtime ASR for Fast and live ASR, diarization for live diarization, or TTS for synthesis. Request bodies differ by endpoint: multipart for Fast, framed binary for live ASR and diarization, and JSON for TTS.
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
## Operations
### [POST · Fast transcription](/en/api-reference/realtime-http/fast-transcription)
Upload one complete bounded audio unit and consume streamed transcript events.
### [POST · Realtime ASR](/en/api-reference/realtime-http/realtime-asr)
Send one framed live-audio chunk and consume partial or final ASR output.
### [POST · Realtime diarization](/en/api-reference/realtime-http/realtime-diarization)
Send one framed live-audio chunk and consume incremental speaker segments.
### [POST · Text to speech](/en/api-reference/realtime-http/text-to-speech)
Capture the undelimited 16 kHz service protocol; use SDK TTS when you need playable audio.
## Production notes
- For live binary requests, keep one stream UUID across chunks and set the start and final flags only at the lifecycle boundaries.
- PCM16 input must be mono, 16 kHz, little-endian, and contain an even number of audio bytes after the control header.
- Send one POST per framed live chunk. A `200` response can contain zero or more NDJSON records. Commit completion only after a record with `is_final: true`; neither the request final bit nor the HTTP response ending proves completion.
- For diarization, keep at most one POST in flight per stream UUID and close each response before sending the next frame. Same-UUID overlap can lose response ownership.
- Treat partial transcripts as replaceable display state and final transcripts as committed output. Do not infer ordering from an opaque `seq` value.
- HTTP TTS service frames contain a UUID, final flag, and PCM16 payload but no payload length or delimiter. Generic HTTP read boundaries cannot reliably recover those frames; prefer SDK Socket.IO TTS and the TTS-to-WAV recipe unless your runtime has an explicit framing mechanism.
## Next steps
### [Realtime HTTP guide](/en/api-guides/realtime-http)
Implement framing, event handling, and cleanup.
### [Socket.IO guide](/en/api-guides/socketio)
Compare the released SDK transport and lifecycle.
---
# Stream Realtime ASR from arriving audio
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/realtime-http/realtime-asr
## Operation
**POST `/http/stt-stream`**
- **Base URL:** `https://api.voice.humain.com/realtime`
- **Request URL:** `https://api.voice.humain.com/realtime/http/stt-stream`
## Description
Canonical direct HTTP operation for Realtime ASR. `POST /http/realtime-asr`
is a compatibility alias; new clients should use this path. JavaScript
and Python SDK `0.18.0` use Socket.IO and do not call either HTTP route.
Send one POST for each audio chunk as it arrives. Prefix every body with
the same 18-byte control header: bytes 0..15 are a fresh nonzero UUID in
raw binary form; byte 16 contains `is_start` in bit 0 and `is_final` in
bit 1; byte 17 is the language (`0=ar`, `1=en`, `2=codeswitch`,
`255=auto`). Keep reserved flag bits zero. Append nonempty raw mono PCM16
little-endian audio at 16 kHz, without a WAV header. Set `is_start` only
on the first chunk, neither flag on intermediate chunks, and `is_final`
on the last chunk with audio; set both for a single-chunk stream.
A `200` response contains zero or more newline-delimited JSON records.
Buffer across network reads and parse complete lines. Treat
`is_speech_final` as a speech boundary. Complete the stream only after
observing `is_final: true`; the request final bit and an HTTP response
ending, including an empty `200`, are not completion signals. Treat
`seq` as opaque and process records in observed arrival order. If output
has started, a later failure ends the partial `200` stream without an
appended JSON error.
Use `X-Api-Key` with the realtime ASR capability from a trusted backend.
Bound every POST/read and the whole stream. Chunk replay and session
resume are not defined; after an ambiguous failure, stop the old stream,
discard provisional state, and restart with a fresh UUID. The public
contract does not define whether chunk POSTs should overlap or be
serialized; use the coordination pattern provisioned for your
environment. A normal non-final response window ending after two seconds
preserves the session. Aborting a POST or timing out the final response
cancels the session. The session also expires after 60 seconds without
accepted client audio or an inference response.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `X-Api-Key`
## Parameters
None documented.
## Request body
- **Required:** yes
#### Content type: `application/octet-stream`
**Schema:**
None documented.
**Examples:**
None documented.
## Responses
### Response `200`
Zero or more Realtime ASR NDJSON records. Once output has started, a
later failure ends the partial stream without an appended JSON
error. Completion requires an observed record with `is_final: true`.
#### Content type: `application/x-ndjson`
**Schema:**
```yaml
type: object
required:
- id
- seq
- transcription
- words
- is_final
- is_speech_final
properties:
id:
type: string
format: uuid
description: Transcription request identifier.
seq:
type: integer
format: int64
description: Opaque diagnostic value with no ordering or uniqueness guarantee.
transcription:
type: string
description: Transcribed text chunk.
words:
type: array
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
description: Word text.
is_final:
type: boolean
description: True only on a record that completes the Realtime ASR stream.
is_speech_final:
type: boolean
description: True at a detected speech-segment boundary; this does not complete the stream.
```
**Examples:**
```yaml
partial:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello wor
words:
- start_time: 0
end_time: 0.45
word: hello
is_speech_final: false
is_final: false
final:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello world
words:
- start_time: 0
end_time: 0.45
word: hello
- start_time: 0.46
end_time: 0.9
word: world
is_speech_final: true
is_final: true
```
### Response `400`
Invalid control header, UUID, language byte, or PCM payload
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
invalid_header:
summary: Header is short or UUID is zero
value:
error: invalid audio upload
code: VALIDATION_FILE_CORRUPT
detail: invalid audio upload
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_language:
summary: Invalid language byte
value:
error: invalid language
code: VALIDATION_INVALID_LANGUAGE
detail: invalid language
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_audio:
summary: PCM payload is empty
value:
error: audio upload is empty
code: VALIDATION_FILE_CORRUPT
detail: audio upload is empty
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
odd_audio:
summary: PCM payload has an odd byte count
value:
error: audio must contain int16 samples
code: VALIDATION_INVALID_FORMAT
detail: audio must contain int16 samples
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant access to the requested voice capability
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `405`
Method not allowed
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `408`
No audio arrived on this pseudo-session within its idle window, so the
session was retired (RFC 9110 15.5.9). Not retryable against the same
session id, which is now tombstoned: start a new session with a new id and
`is_start`.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
session_went_idle:
value:
error: session idle timeout exceeded; start a new session
code: SESSION_IDLE_TIMEOUT
detail: session idle timeout exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 900
observed: 901
unit: seconds
bound: session_idle
```
### Response `409`
The chunk conflicts with the state of its pseudo-session (RFC 9110
15.5.10): the id was never started, has already been retired, or an
`is_start` arrived for an id that is already live. One answer covers all
of them, so timing cannot change the contract. Start a new session with a
new id.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
not_live:
value:
error: session is not live; start a new session with is_start and a new id
code: SESSION_EXPIRED
detail: session is not live; start a new session with is_start and a new id
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `413`
The request body exceeded the configured byte limit for this audio route:
64 MiB for Fast uploads, 16 MiB for Realtime ASR frames, 16 MiB for
Realtime diarization frames. Non-retryable at the same size; resend a
smaller unit or chunk.
`data.bound` names which byte limit was hit - `fast_audio_bytes`,
`realtime_asr_frame_bytes`, or `realtime_diarization_frame_bytes`.
`data.observed` is the exact request size when the client declared a
`Content-Length`, and otherwise a MINIMUM (the limit plus one byte),
because a body with no declared length is cut off mid-read and its true
size is never learned.
This status is only ever reached from a BYTE count. A request whose bytes
are acceptable but whose decoded audio is too long is `422` with
`AUDIO_DURATION_EXCEEDED` instead.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
declared_length_over_the_cap:
summary: Content-Length was declared, so observed is exact
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 20971520
unit: bytes
bound: realtime_asr_frame_bytes
streamed_body_over_the_cap:
summary: No declared length, so observed is the limit plus one byte
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 67108864
observed: 67108865
unit: bytes
bound: fast_audio_bytes
```
### Response `422`
The request parsed correctly and its bytes were acceptable, but the
amount of AUDIO it asks the service to process exceeds this endpoint's
ceiling (RFC 9110 15.5.21). A small compressed upload that decodes to
many hours is exactly this case, which is why it is not `413`.
`data.bound` names which audio ceiling was hit:
* `fast_audio_duration` - one Fast submission decoded to more than 1800
seconds. Split the recording or use the batch transcription API.
* `session_audio_duration` - a realtime session has now sent more total
audio content than its 14400-second (4 hour) allowance. The session is
retired; start a new one.
`data.observed` is in whole seconds, rounded up. Where the service
stopped decoding at the ceiling it never learned the true total length,
so the observed value is a MINIMUM rather than an exact measurement.
Not retryable: resending the identical audio cannot succeed. Shorten the
unit, or move to the batch API.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
fast_decoded_audio_too_long:
value:
error: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
code: AUDIO_DURATION_EXCEEDED
detail: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1800
observed: 3601
unit: seconds
bound: fast_audio_duration
session_audio_allowance_spent:
value:
error: session maximum audio duration exceeded; start a new session
code: AUDIO_DURATION_EXCEEDED
detail: session maximum audio duration exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 14400
observed: 14401
unit: seconds
bound: session_audio_duration
```
### Response `429`
A realtime request was throttled. Three distinct sources share this
status on these routes and the `code` field distinguishes them:
* `SESSION_BYTE_RATE_EXCEEDED` - audio is arriving faster than the
session's sustained rate allows (four times real time, with a 16 MiB
burst). Honour `Retry-After`; the identical payload then succeeds. The
session stays live. `data.bound` is `session_audio_rate_burst`.
* `CONCURRENCY_LIMIT_EXCEEDED` - the billable account already has as many
concurrent operations of this kind in flight as its plan allows.
`data.bound` is `account_concurrency_`.
* `SESSION_SLOTS_EXHAUSTED` - the account holds as many concurrent HTTP
pseudo-sessions as this process allows.
The gateway's per-key request-RATE limit also answers `429`, reports
`RATE_LIMIT_EXCEEDED`, and has a deployment-specific body shape. All of
these are retryable and none consumes credit or quota.
**Headers:**
```yaml
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
examples:
- 2
```
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
audio_arriving_too_fast:
value:
error: audio is arriving faster than this session allows; slow down to real time and retry
code: SESSION_BYTE_RATE_EXCEEDED
detail: audio is arriving faster than this session allows; slow down to real time and retry
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 33554432
unit: bytes
bound: session_audio_rate_burst
account_concurrency_exhausted:
value:
error: too many concurrent operations for this account
code: CONCURRENCY_LIMIT_EXCEEDED
detail: too many concurrent operations for this account
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 8
observed: 8
unit: operations
bound: account_concurrency_realtime_asr
```
### Response `500`
Realtime ASR failed before a final record was emitted
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
transcription_failed:
value:
error: realtime ASR transcription failed
code: ASR_TRANSCRIPTION_FAILED
detail: realtime ASR transcription failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
Build the live lifecycle next: reuse one stream UUID across framed chunks, replace partial display state, commit only final results, and end every wait with an application deadline.
### [Frame live HTTP audio](/en/api-guides/realtime-http)
Construct request frames and reconcile zero or more NDJSON records per response.
### [Use the Socket.IO SDK](/en/api-guides/socketio)
Follow the released SDK lifecycle when you do not need direct HTTP.
---
# Build a speaker timeline from arriving audio
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/realtime-http/realtime-diarization
## Operation
**POST `/http/diarization-stream`**
- **Base URL:** `https://api.voice.humain.com/realtime`
- **Request URL:** `https://api.voice.humain.com/realtime/http/diarization-stream`
## Description
Use this operation to build a speaker timeline while PCM audio is still
arriving. It does not transcribe speech or identify real people.
JavaScript and Python SDK `0.18.0` use Socket.IO; they do not issue this
HTTP request.
From a trusted backend, send one complete binary frame per POST with
`X-Api-Key` and the diarization capability. Reuse one fresh nonzero UUID
until the stream ends, and keep at most one POST in flight for that UUID.
Concurrent requests for the same UUID can overwrite response ownership.
Capture audio into a bounded queue and have one sender drain it, closing
each response before sending the next frame. Distinct UUID streams can
run concurrently.
Every frame has an 18-byte header followed by nonempty raw mono PCM16
little-endian audio at 16 kHz. Bytes 0..15 are the UUID. In byte 16, bit
0 is `is_start` and bit 1 is `is_final`; reserved bits 2..7 MUST be zero
and a frame that sets any of them is rejected with `400`
`VALIDATION_INVALID_FORMAT`.
Byte 17 must be `0` (Arabic), `1` (English), `2` (code-switch), or `255`
(auto), but is discarded after validation and does not change
diarization. Set start only on the first frame, final on the last real
audio frame, and both (`0x03`) for a one-frame stream. Every request must
include a nonempty even-length PCM payload; there is no empty terminator.
Each `200` can contain zero or more NDJSON records. Buffer network reads
and split only on newline. Aggregate records across every response for
the UUID. Accumulate unseen `final_segments` deltas, replace the previous
`active_segments` snapshot, and sort the reconciled timeline by
`start_time`. Speaker labels are relative to one stream, not identities.
Segment times are seconds from the stream start. Retain a nonempty active
tail in a final record as provisional; do not relabel it finalized.
Only an observed record with `is_final: true` completes the stream. A
final request bit, an empty `200`, response EOF, or timeout does not. If
output has started, a later failure ends the partial `200` stream without
an appended JSON error. A normal non-final response window ending after
two seconds preserves the session. Aborting a POST or timing out the
final response cancels the session, and the session expires after 60
seconds without client or inference activity. There is no HTTP chunk replay,
resume, or idempotency contract. After an ambiguous failure, stop the
producer, close every response, preserve the timeline as incomplete, and
recover with a fresh UUID instead of replaying an old chunk.
The service selects the realtime diarization model; clients have no model
selector. Missing model configuration returns
`400 DIARIZATION_MODEL_NOT_FOUND`. Backend capacity and inference errors
currently collapse to retryable `500 DIARIZATION_FAILED`; a production
gateway can independently return `429` with deployment-specific details.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `X-Api-Key`
## Parameters
None documented.
## Request body
- **Required:** yes
#### Content type: `application/octet-stream`
**Schema:**
None documented.
**Examples:**
None documented.
## Responses
### Response `200`
Zero or more diarization NDJSON records. Once output has started, a
later failure ends the partial stream without an appended JSON
error. Completion requires an observed record with `is_final: true`.
**Headers:**
```yaml
Cache-Control:
schema:
type: string
enum:
- no-store
description: Prevents intermediaries from caching speaker-timeline records.
```
#### Content type: `application/x-ndjson`
**Schema:**
```yaml
type: object
required:
- id
- final_segments
- active_segments
- is_final
properties:
id:
type: string
format: uuid
description: Diarization request identifier.
final_segments:
type: array
description: |
Newly finalized segments in this record. Accumulate unseen segments
across records; this is not a cumulative timeline snapshot.
items:
type: object
required:
- start_time
- end_time
- speaker
properties:
start_time:
type: number
format: float
description: Segment start time in seconds relative to the stream start.
end_time:
type: number
format: float
description: Segment end time in seconds relative to the stream start.
speaker:
type: string
description: Stream-relative label such as SPEAKER_01, not a real-world identity.
active_segments:
type: array
description: |
Replacement snapshot of evolving segments. Replace, rather than
append to, the previous active snapshot. A final record can retain a
nonempty best-known provisional tail.
items:
type: object
required:
- start_time
- end_time
- speaker
properties:
start_time:
type: number
format: float
description: Segment start time in seconds relative to the stream start.
end_time:
type: number
format: float
description: Segment end time in seconds relative to the stream start.
speaker:
type: string
description: Stream-relative label such as SPEAKER_01, not a real-world identity.
is_final:
type: boolean
description: True only on a record that completes the diarization stream.
```
**Examples:**
```yaml
incremental:
summary: Final-segment delta plus current active snapshot
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
final_segments:
- start_time: 0
end_time: 1.5
speaker: SPEAKER_01
active_segments:
- start_time: 1.5
end_time: 3
speaker: SPEAKER_02
is_final: false
final:
summary: Later final delta with a best-known provisional tail
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
final_segments:
- start_time: 1.5
end_time: 3
speaker: SPEAKER_02
active_segments:
- start_time: 3
end_time: 3.4
speaker: SPEAKER_01
is_final: true
```
### Response `400`
Invalid diarization frame, stream start, or service model configuration
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
invalid_header:
summary: Header is short or UUID is zero
value:
error: invalid audio upload
code: VALIDATION_FILE_CORRUPT
detail: invalid audio upload
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_language:
summary: Language byte is not 0, 1, 2, or 255
value:
error: invalid language
code: VALIDATION_INVALID_LANGUAGE
detail: invalid language
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_audio:
summary: PCM payload is empty
value:
error: audio upload is empty
code: VALIDATION_FILE_CORRUPT
detail: audio upload is empty
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
odd_audio:
summary: PCM payload has an odd byte count
value:
error: audio must contain int16 samples
code: VALIDATION_INVALID_FORMAT
detail: audio must contain int16 samples
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
missing_start:
summary: First frame does not set the start bit
value:
error: missing is_start flag
code: VALIDATION_REQUIRED_FIELD
detail: missing is_start flag
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
missing_model:
summary: Realtime diarization is not configured
value:
error: diarization model not found
code: DIARIZATION_MODEL_NOT_FOUND
detail: diarization model not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant access to the requested voice capability
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `405`
Method not allowed
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `408`
No audio arrived on this pseudo-session within its idle window, so the
session was retired (RFC 9110 15.5.9). Not retryable against the same
session id, which is now tombstoned: start a new session with a new id and
`is_start`.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
session_went_idle:
value:
error: session idle timeout exceeded; start a new session
code: SESSION_IDLE_TIMEOUT
detail: session idle timeout exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 900
observed: 901
unit: seconds
bound: session_idle
```
### Response `409`
The chunk conflicts with the state of its pseudo-session (RFC 9110
15.5.10): the id was never started, has already been retired, or an
`is_start` arrived for an id that is already live. One answer covers all
of them, so timing cannot change the contract. Start a new session with a
new id.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
not_live:
value:
error: session is not live; start a new session with is_start and a new id
code: SESSION_EXPIRED
detail: session is not live; start a new session with is_start and a new id
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `413`
The request body exceeded the configured byte limit for this audio route:
64 MiB for Fast uploads, 16 MiB for Realtime ASR frames, 16 MiB for
Realtime diarization frames. Non-retryable at the same size; resend a
smaller unit or chunk.
`data.bound` names which byte limit was hit - `fast_audio_bytes`,
`realtime_asr_frame_bytes`, or `realtime_diarization_frame_bytes`.
`data.observed` is the exact request size when the client declared a
`Content-Length`, and otherwise a MINIMUM (the limit plus one byte),
because a body with no declared length is cut off mid-read and its true
size is never learned.
This status is only ever reached from a BYTE count. A request whose bytes
are acceptable but whose decoded audio is too long is `422` with
`AUDIO_DURATION_EXCEEDED` instead.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
declared_length_over_the_cap:
summary: Content-Length was declared, so observed is exact
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 20971520
unit: bytes
bound: realtime_asr_frame_bytes
streamed_body_over_the_cap:
summary: No declared length, so observed is the limit plus one byte
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 67108864
observed: 67108865
unit: bytes
bound: fast_audio_bytes
```
### Response `422`
The request parsed correctly and its bytes were acceptable, but the
amount of AUDIO it asks the service to process exceeds this endpoint's
ceiling (RFC 9110 15.5.21). A small compressed upload that decodes to
many hours is exactly this case, which is why it is not `413`.
`data.bound` names which audio ceiling was hit:
* `fast_audio_duration` - one Fast submission decoded to more than 1800
seconds. Split the recording or use the batch transcription API.
* `session_audio_duration` - a realtime session has now sent more total
audio content than its 14400-second (4 hour) allowance. The session is
retired; start a new one.
`data.observed` is in whole seconds, rounded up. Where the service
stopped decoding at the ceiling it never learned the true total length,
so the observed value is a MINIMUM rather than an exact measurement.
Not retryable: resending the identical audio cannot succeed. Shorten the
unit, or move to the batch API.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
fast_decoded_audio_too_long:
value:
error: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
code: AUDIO_DURATION_EXCEEDED
detail: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1800
observed: 3601
unit: seconds
bound: fast_audio_duration
session_audio_allowance_spent:
value:
error: session maximum audio duration exceeded; start a new session
code: AUDIO_DURATION_EXCEEDED
detail: session maximum audio duration exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 14400
observed: 14401
unit: seconds
bound: session_audio_duration
```
### Response `429`
A realtime request was throttled. Three distinct sources share this
status on these routes and the `code` field distinguishes them:
* `SESSION_BYTE_RATE_EXCEEDED` - audio is arriving faster than the
session's sustained rate allows (four times real time, with a 16 MiB
burst). Honour `Retry-After`; the identical payload then succeeds. The
session stays live. `data.bound` is `session_audio_rate_burst`.
* `CONCURRENCY_LIMIT_EXCEEDED` - the billable account already has as many
concurrent operations of this kind in flight as its plan allows.
`data.bound` is `account_concurrency_`.
* `SESSION_SLOTS_EXHAUSTED` - the account holds as many concurrent HTTP
pseudo-sessions as this process allows.
The gateway's per-key request-RATE limit also answers `429`, reports
`RATE_LIMIT_EXCEEDED`, and has a deployment-specific body shape. All of
these are retryable and none consumes credit or quota.
**Headers:**
```yaml
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
examples:
- 2
```
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
audio_arriving_too_fast:
value:
error: audio is arriving faster than this session allows; slow down to real time and retry
code: SESSION_BYTE_RATE_EXCEEDED
detail: audio is arriving faster than this session allows; slow down to real time and retry
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 33554432
unit: bytes
bound: session_audio_rate_burst
account_concurrency_exhausted:
value:
error: too many concurrent operations for this account
code: CONCURRENCY_LIMIT_EXCEEDED
detail: too many concurrent operations for this account
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 8
observed: 8
unit: operations
bound: account_concurrency_realtime_asr
```
### Response `500`
Diarization failed before a final record was emitted. Backend capacity
and inference failures currently collapse to this retryable response.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
diarization_failed:
value:
error: realtime diarization failed
code: DIARIZATION_FAILED
detail: realtime diarization failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
Complete the live stream lifecycle before consuming speaker labels: keep one UUID across framed chunks, serialize same-UUID POSTs, reconcile final deltas with the latest active snapshot, and clean up on a final result, structured error, or deadline.
### [Implement HTTP diarization](/en/api-guides/realtime-http)
Apply the binary frame contract and incremental-result lifecycle.
### [Compare the SDK transport](/en/api-guides/socketio)
Use the released Socket.IO client when it better matches your application.
---
# Capture an HTTP TTS service-frame stream
Locale: en
Source: https://docs.voice.humain.com/en/api-reference/realtime-http/text-to-speech
## Operation
**POST `/http/tts`**
- **Base URL:** `https://api.voice.humain.com/realtime`
- **Request URL:** `https://api.voice.humain.com/realtime/http/tts`
## Description
This is a direct platform HTTP operation. JavaScript and Python SDK
`0.18.0` use Socket.IO and do not call this route. Send it from a
trusted backend with `X-Api-Key` and the TTS capability.
Send a fresh UUID `id`, top-level `text` containing at least one Unicode
letter or number after trimming, and the explicit model key `nebula`.
For predictable voice selection, send exactly one `voice_id` or one
`voice_references` entry, never both. Obtain a `voice_id` through SDK
`listVoices()` or `list_voices()`; no HTTP voice-list operation exists.
The returned UUID identifies one of the seven multilingual voice
profiles. Its physical variants are internal and direct use of a
physical variant UUID is rejected.
If `model` is omitted, the deployment uses its configured default model
key, falling back to `nebula`. If the voice selector is omitted, voice
selection is deployment-specific.
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 these limits with `TTS_MAX_INPUT_CHARACTERS_FREE`,
`TTS_MAX_INPUT_CHARACTERS_STANDARD`, and
`TTS_MAX_INPUT_CHARACTERS_ENTERPRISE`, so this schema intentionally does
not declare a fixed `maxLength`.
Reference `audio` must be standard-base64 RIFF/WAVE containing nonempty
mono PCM16 audio, accompanied by its transcript.
An HTTP `200` body is an undelimited sequence of service frames: 16 raw
UUID bytes, one final-flag byte, then 16 kHz PCM16 little-endian bytes.
Ordinary HTTP read boundaries do not preserve service-frame boundaries,
so this body is neither generically decodable raw PCM nor WAV. Save it
only as a protocol capture. Use Socket.IO TTS and the TTS-to-WAV recipe
for playable output.
Apply finite connect, inactivity/read, and overall deadlines. EOF or
cancellation without a boundary-aware final flag is incomplete.
Aborting the HTTP request cancels only its in-flight synthesis. A
failure after bytes were committed ends the partial binary stream; the
service never appends an error JSON document to a binary `200` body.
Keep partial bytes separate from complete output. This operation has no
idempotency contract; use a fresh UUID for an application-approved
retry.
## Authentication
- `ApiKeyAuth` — type: `apiKey`; Location: `header`; Headers: `X-Api-Key`
## Parameters
None documented.
## Request body
- **Required:** yes
#### Content type: `application/json`
**Schema:**
```yaml
type: object
additionalProperties: false
required:
- id
- text
not:
required:
- voice_id
- voice_references
properties:
voice_id: {}
voice_references:
type: array
properties:
id:
type: string
format: uuid
description: Fresh correlation UUID echoed in service-frame headers. It is not an idempotency key.
text:
type: string
minLength: 1
description: |
Text 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 HTTP 400 with
`retryable: false`, 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 tier limit is HTTP **422** with code
`CHARACTER_COUNT_EXCEEDED`, `retryable: false`, and a `data` object
whose `bound` is `tts_input_characters`, `unit` is `characters`,
`limit` is the configured ceiling and `observed` is the code-point
count. A count is a semantic workload unit rather than a
representation size, which is why it is 422 and not 413.
This field 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. Do not send SSML and do not rely on any markup semantics.
model:
type: string
minLength: 1
description: |
Provisioned model key. If omitted, the deployment uses its configured
default model key, falling back to `nebula`. Use `nebula` in portable examples.
voice_id:
type: string
format: uuid
description: |
Profile UUID obtained through Socket.IO or SDK voice listing. There
is no HTTP voice-list operation. The Arabic variant is selected when
`text` contains any Unicode Arabic-script letter; otherwise the
English variant is selected. Physical variant UUIDs are internal
and rejected. Do not combine this with
`voice_references`: supplying both is rejected with HTTP 400,
`VALIDATION_INVALID_PARAM` and `retryable: false`, and synthesis is
not attempted. An explicit empty `voice_references` array counts as
supplying it, but `null` does NOT — `voice_id` together with
`voice_references: null` is valid and uses `voice_id`.
voice_references:
type:
- array
- "null"
minItems: 1
maxItems: 1
description: |
Exactly one reference clip for voice adaptation. Do not combine this
with `voice_id`. The `maxItems: 1` bound is enforced at runtime:
supplying more is rejected with HTTP **422**,
`VOICE_REFERENCE_COUNT_EXCEEDED`, `retryable: false`, and a `data`
object whose `bound` is `tts_voice_reference_count` and `unit` is
`references`. Every bound on this array and its contents is checked
before any model lookup, admission or charge.
Three ways of saying "no reference" are NOT equivalent:
* OMITTING the property, or sending `null`, both mean "no reference".
`null` is accepted for client compatibility, because many clients
and generated SDKs serialize an unset optional field as `null`, and
it is declared here as `nullable: true` rather than merely
tolerated. `voice_id` combined with `null` is therefore valid and
uses `voice_id`: a null is not a second voice selector.
* An explicit EMPTY ARRAY `[]` is rejected with HTTP 400 and
`VALIDATION_INVALID_PARAM`. It is a well-formed array that violates
the declared `minItems: 1`, so unlike `null` it is a constraint
violation rather than an absent value. Omit the property or send
`null` instead.
items:
type: object
additionalProperties: false
required:
- audio
- text
properties:
audio:
type: string
minLength: 1
description: |
Standard-base64 RIFF/WAVE containing nonempty mono PCM16 reference
audio. The base64 must be strictly canonical: line breaks, spaces,
the URL-safe alphabet and non-zero padding bits are all rejected
with HTTP 400 and `VALIDATION_INVALID_FORMAT`, as is anything that
is not a mono PCM16 RIFF/WAVE file.
Two ceilings apply, both derived from the deployed model and both
checked before any model lookup, admission or charge. The size
ceiling is evaluated arithmetically from the base64 length BEFORE the
payload is decoded, so an oversized reference is never materialised;
the duration ceiling necessarily follows decoding and WAV parsing.
Decoded size must not exceed
the deployment's byte ceiling, default **2 MiB** — exceeding it is
HTTP **413**, `PAYLOAD_TOO_LARGE`, with `data.bound`
`tts_voice_reference_bytes` and `unit` `bytes`, because the
rejection is reached from a byte count. Decoded duration must not
exceed the deployment's duration ceiling, default **15 seconds** —
exceeding it is HTTP **422**, `AUDIO_DURATION_EXCEEDED`, with
`data.bound` `tts_voice_reference_duration` and `unit` `seconds`.
The duration ceiling matches the deployed model's own reference
limit, above which the extra audio was never used. Duration is
computed from the file's own declared sample rate, so a clip at any
sample rate is measured in real seconds. Both bounds are inclusive:
a clip exactly at the ceiling is accepted.
contentEncoding: base64
text:
type: string
minLength: 1
maxLength: 500
description: |
Nonempty transcript corresponding to the reference audio, counted in
Unicode code points. It must contain at least one Unicode letter or
number: missing or whitespace-only text is rejected with HTTP 400
and `VALIDATION_REQUIRED_FIELD`, and text with no letter or number
with HTTP 400 and `VALIDATION_INVALID_PARAM`. Exceeding the ceiling
is HTTP **422**, `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: it describes one
fixed-duration reference clip rather than the synthesis workload.
A deployment may lower it but never raise it.
```
**Examples:**
```yaml
basic:
summary: Deployment-selected voice
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
text: Hello from HUMAIN Voice
model: nebula
with_voice:
summary: Explicit voice selected through the SDK voice list
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
text: Welcome to HUMAIN Voice
model: nebula
voice_id: af52a907-1086-46f7-8f5d-72317875d7bd
```
## Responses
### Response `200`
Undelimited TTS service-frame sequence, not raw PCM or WAV. Ordinary
HTTP read chunks are not service-frame boundaries. Only a client
with an environment-specific framing mechanism can identify the
final flag; EOF alone does not prove completion.
#### Content type: `application/octet-stream`
**Schema:**
None documented.
**Examples:**
None documented.
### Response `400`
Malformed input, including an unparseable request `id`, or missing/unusable
text or voice reference. These validation failures are non-retryable and
occur before synthesis begins.
Valid text rejected by the TTS content policy is also reported here as
`TTS_INPUT_NOT_ALLOWED`. It is non-retryable: the same text will not be
accepted, so change the text before sending another request.
A malformed request `id` is reported as `VALIDATION_INVALID_FORMAT`,
together with every other malformed-body failure: the `id` is parsed
during JSON decoding, so an unparseable value fails the whole body rather
than reaching a dedicated check. The request `id` itself never yields
`VALIDATION_INVALID_UUID` on this route.
A caller-supplied `voice_id` IS reported here (SAU-2258): a `voice_id`
that is not a valid UUID is `VALIDATION_INVALID_UUID`, and a well-formed
`voice_id` that does not identify an available voice is
`TTS_VOICE_NOT_FOUND`. Both are `400` and non-retryable — resending the
same `voice_id` cannot succeed; fix it or send `voice_references`
instead. (Voice data that is present but incomplete or corrupt, or a
proven storage/database outage, are server-side conditions reported as
`500`/`503` — see the `500` and `503` responses.)
Text and reference OVERAGES are not here: exceeding the tier character
limit, the reference transcript limit or the reference count is `422`,
and an oversized decoded reference is `413`.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
invalid_body:
value:
error: Invalid request body
code: VALIDATION_INVALID_FORMAT
detail: Invalid request body
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_id:
summary: The request `id` is not a valid UUID, so the body fails to decode
value:
error: Invalid request body
code: VALIDATION_INVALID_FORMAT
detail: Invalid request body
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_text:
summary: Text is empty or contains only Unicode whitespace
value:
error: TTS input must contain non-whitespace text
code: VALIDATION_REQUIRED_FIELD
detail: TTS input must contain non-whitespace text
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
voice_selector_conflict:
summary: voice_id and voice_references were both supplied
value:
error: voice_id and voice_references are mutually exclusive
code: VALIDATION_INVALID_PARAM
detail: voice_id and voice_references are mutually exclusive
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_voice_reference_array:
summary: An explicit empty array; omit the property instead
value:
error: voice_references must contain exactly one reference when present; omit the field to use the default voice
code: VALIDATION_INVALID_PARAM
detail: voice_references must contain exactly one reference when present; omit the field to use the default voice
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
reference_audio_not_a_wav:
summary: Reference audio is not canonical base64 mono PCM16 RIFF/WAVE
value:
error: "voice_references[0].audio is not valid reference audio: audio must be a RIFF/WAVE file"
code: VALIDATION_INVALID_FORMAT
detail: "voice_references[0].audio is not valid reference audio: audio must be a RIFF/WAVE file"
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
reference_text_missing:
summary: Reference transcript is missing or whitespace-only
value:
error: voice_references[0].text must contain the reference transcript
code: VALIDATION_REQUIRED_FIELD
detail: voice_references[0].text must contain the reference transcript
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_voice_id:
summary: voice_id is present but not a valid UUID
value:
error: voice_id must be a valid UUID
code: VALIDATION_INVALID_UUID
detail: voice_id must be a valid UUID
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
voice_id_not_found:
summary: voice_id is a valid UUID but does not identify an available voice
value:
error: voice_id does not identify an available voice
code: TTS_VOICE_NOT_FOUND
detail: voice_id does not identify an available voice
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
input_not_allowed:
summary: Text rejected by the TTS content policy
value:
error: TTS input is not allowed
code: TTS_INPUT_NOT_ALLOWED
detail: TTS input is not allowed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `401`
Unauthorized
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `403`
The API key does not grant access to the requested voice capability
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `405`
Method not allowed
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `413`
The request body exceeded the configured limit for this route (16 MiB for
TTS request bodies). This failure is non-retryable at the same size; send
a smaller request.
The request-BODY form of this response carries no `data` object. The three
audio routes answer an oversized body with the same status and code but DO
include `data`; see their own `413` documentation.
`POST /http/tts` also answers this status when a voice reference's DECODED
audio exceeds the deployment's per-reference byte ceiling (default 2 MiB),
and that form DOES carry `data` with `bound`
`tts_voice_reference_bytes` and `unit` `bytes`. It is checked from the
base64 length before the payload is decoded, so an oversized reference is
never materialised.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
body_too_large:
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
voice_reference_too_large:
summary: Decoded reference audio exceeds the per-reference byte ceiling
value:
error: voice_references[0].audio decodes to 3145728 bytes; limit is 2097152
code: PAYLOAD_TOO_LARGE
detail: voice_references[0].audio decodes to 3145728 bytes; limit is 2097152
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 2097152
observed: 3145728
unit: bytes
bound: tts_voice_reference_bytes
```
### Response `422`
The request parsed correctly and every field is individually valid, but a
SEMANTIC workload unit exceeds its ceiling (RFC 9110 15.5.21). A few
hundred bytes of text can ask for far more synthesis work than its size
suggests, so these bounds cannot be expressed as a byte cap and are
never `413`.
`data.bound` names which ceiling was hit:
* `tts_input_characters` - `text` is longer than the account tier's
character limit (defaults: 500 free, 1,000 standard and enterprise).
* `tts_voice_reference_text_characters` - `voice_references[0].text` is
longer than the reference-transcript limit (default 500).
* `tts_voice_reference_count` - more than one entry in
`voice_references`; the published `maxItems` is 1.
* `tts_voice_reference_duration` - the decoded reference audio is longer
than the deployment's ceiling (default 15 seconds), which matches the
deployed model's own reference limit. `data.observed` is in whole
seconds, rounded up.
Every one of these is checked before any model lookup, admission or
charge, so a rejected request consumes no quota and no concurrency slot.
Not retryable: resending the identical request cannot succeed.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
text_too_long:
summary: Text exceeds the default free-tier runtime limit
value:
error: TTS input contains 501 characters; limit is 500
code: CHARACTER_COUNT_EXCEEDED
detail: TTS input contains 501 characters; limit is 500
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 500
observed: 501
unit: characters
bound: tts_input_characters
reference_text_too_long:
summary: Reference transcript exceeds its own independent limit
value:
error: voice_references[0].text contains 501 characters; limit is 500
code: CHARACTER_COUNT_EXCEEDED
detail: voice_references[0].text contains 501 characters; limit is 500
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 500
observed: 501
unit: characters
bound: tts_voice_reference_text_characters
too_many_voice_references:
summary: More than the published maxItems of 1
value:
error: voice_references contains 2 references; limit is 1
code: VOICE_REFERENCE_COUNT_EXCEEDED
detail: voice_references contains 2 references; limit is 1
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1
observed: 2
unit: references
bound: tts_voice_reference_count
reference_audio_too_long:
summary: Reference clip longer than the deployed model's reference limit
value:
error: voice_references[0].audio is 16 seconds long; limit is 15
code: AUDIO_DURATION_EXCEEDED
detail: voice_references[0].audio is 16 seconds long; limit is 15
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 15
observed: 16
unit: seconds
bound: tts_voice_reference_duration
```
### Response `429`
The account already has as many concurrent operations of this kind in
flight as its plan allows, counted across every server instance
(SAU-2181). The limit is per BILLABLE ACCOUNT, so several API keys
belonging to one account share a single allowance and creating more keys
does not raise it. Each workload has its own allowance, so realtime ASR
and TTS do not compete with one another.
This is RETRYABLE and usually clears within seconds, as soon as one of
the account's in-flight operations finishes. Honour the `Retry-After`
header.
Do not confuse this with the other 429 on these routes: the gateway's
per-key REQUEST-RATE limit reports `RATE_LIMIT_EXCEEDED`, and the
per-connection HTTP session cap reports `SESSION_SLOTS_EXHAUSTED`. The
`code` field distinguishes them. No credit or quota is consumed by a
rejection.
**Headers:**
```yaml
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
examples:
- 5
```
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
account_concurrency_exhausted:
value:
error: too many concurrent operations for this account
code: CONCURRENCY_LIMIT_EXCEEDED
detail: too many concurrent operations for this account
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 4
observed: 4
unit: operations
bound: account_concurrency_tts
```
### Response `500`
TTS failed before binary output was committed. If output was already
committed, the partial binary `200` stream ends without an appended JSON
error.
This status carries two distinct codes. `TTS_SYNTHESIS_FAILED` is the
retryable case: a model-resolution, capacity, or inference failure that a
later attempt may clear. `TTS_VOICE_RESOLUTION_FAILED` (SAU-2258) is
non-retryable: a resolved voice whose stored data is incomplete or
corrupt (missing audio or transcript, an unusable stored URI, or audio
that is not INT16 PCM), or an unclassified database/storage error.
Resending the identical request cannot fix broken server-side voice data.
Text and voice-REFERENCE validation failures do NOT reach here: they are
reported as `400`, `413` or `422` with a specific code before synthesis
begins. A caller-supplied `voice_id` that is invalid or unknown is also
not here — it is `400` (`VALIDATION_INVALID_UUID` / `TTS_VOICE_NOT_FOUND`);
a proven database/storage outage during voice resolution is `503`
(`SERVER_DEPENDENCY_FAILURE`, retryable).
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
synthesis_failed:
summary: Retryable model/capacity/inference failure
value:
error: TTS synthesis failed
code: TTS_SYNTHESIS_FAILED
detail: TTS synthesis failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
voice_resolution_failed:
summary: Resolved voice has incomplete/corrupt stored data (non-retryable)
value:
error: selected voice could not be resolved
code: TTS_VOICE_RESOLUTION_FAILED
detail: selected voice could not be resolved
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### Response `503`
A required dependency was temporarily unavailable. The response is
retryable: the identical request may succeed once that dependency
recovers.
`TTS_MODERATION_UNAVAILABLE` means the content-moderation authority could
not make a decision, so synthesis failed closed. It is deliberately
distinct from `TTS_INPUT_NOT_ALLOWED`: an infrastructure failure must not
be reported as a policy rejection.
`SERVER_DEPENDENCY_FAILURE` is a positively-classified transient database
or object-storage outage while resolving `voice_id` (SAU-2258). It is
distinct from `500 TTS_VOICE_RESOLUTION_FAILED`, which identifies broken
server-side voice data that a retry cannot fix. Both checks run before
quota deduction, rate-limit charge or inference, so a retried request is
not double-charged.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
voice_resolution_unavailable:
summary: Transient database/storage outage during voice resolution
value:
error: voice resolution is temporarily unavailable
code: SERVER_DEPENDENCY_FAILURE
detail: voice resolution is temporarily unavailable
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
moderation_unavailable:
summary: Content-moderation authority temporarily unavailable
value:
error: TTS moderation is unavailable
code: TTS_MODERATION_UNAVAILABLE
detail: TTS moderation is unavailable
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
### Response `504`
The non-resetting 25-second synthesis deadline elapsed before a complete
protocol-final result was available. This response is retryable and is
returned only when binary output has not started; otherwise the partial
binary stream ends without appended JSON.
#### Content type: `application/json`
**Schema:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: Legacy error identifier (frozen for backward compatibility)
message:
type: string
description: Legacy message field (present only on auth missing-key errors)
code:
type: string
description: |
Machine-readable error code. This enumeration is the set reachable
on the four HTTP routes in this document. The Socket.IO surface
emits a different set, including `SERVER_INTERNAL`,
`RATE_LIMIT_EXCEEDED`, `RATE_LIMIT_SERVICE_BUSY`,
`TTS_MODEL_NOT_FOUND`, and `TTS_VOICE_LIST_FAILED`; see the AsyncAPI
documents. A `429` on these routes has two distinct sources: the
gateway's per-key request-rate limit, which reports
`RATE_LIMIT_EXCEEDED` and whose body shape is deployment-specific,
and the service's own admission control, which reports
`CONCURRENCY_LIMIT_EXCEEDED`, `SESSION_SLOTS_EXHAUSTED` or
`SESSION_BYTE_RATE_EXCEEDED` in this schema with a `Retry-After`
header.
The `SESSION_*` codes are reachable only on the two multi-POST
realtime routes, which maintain a keyed pseudo-session across
requests: `SESSION_BYTES_EXCEEDED` is `413`,
`SESSION_DURATION_EXCEEDED` and `AUDIO_DURATION_EXCEEDED` are `422`,
`SESSION_IDLE_TIMEOUT` is `408`, `SESSION_EXPIRED` is `409`, and
`SESSION_SLOTS_EXHAUSTED` and `SESSION_BYTE_RATE_EXCEEDED` are `429`.
`CHARACTER_COUNT_EXCEEDED` and `VOICE_REFERENCE_COUNT_EXCEEDED` are
`422` and are reachable only on `POST /http/tts`. Both carry `data`.
`data.bound` distinguishes the two character ceilings:
`tts_input_characters` for `text`, and
`tts_voice_reference_text_characters` for
`voice_references[0].text`. On the same route
`AUDIO_DURATION_EXCEEDED` with `data.bound`
`tts_voice_reference_duration` reports reference audio longer than
the deployment's ceiling, and `PAYLOAD_TOO_LARGE` with `data.bound`
`tts_voice_reference_bytes` reports reference audio whose decoded
size exceeds it.
`POST /http/tts` also reports `voice_id` resolution outcomes
(SAU-2258): `VALIDATION_INVALID_UUID` (`400`) for a malformed
`voice_id`, `TTS_VOICE_NOT_FOUND` (`400`) for a well-formed `voice_id`
that does not identify an available voice,
`TTS_VOICE_RESOLUTION_FAILED` (`500`, non-retryable) for a resolved
voice with incomplete or corrupt stored data, and
`SERVER_DEPENDENCY_FAILURE` (`503`, retryable) for a positively
classified transient database/storage outage during resolution.
Its content guard reports `TTS_INPUT_NOT_ALLOWED` (`400`,
non-retryable) when the text is rejected by policy and
`TTS_MODERATION_UNAVAILABLE` (`503`, retryable) when moderation
cannot make a decision and synthesis fails closed.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: Human-readable error explanation
job_id:
type: string
format: uuid
description: Correlation UUID when available; on streaming routes this is the stream UUID despite the legacy field name
retryable:
type: boolean
description: Whether the client should retry this request
timestamp:
type: string
format: date-time
description: ISO 8601 timestamp of when the error occurred
data:
type: object
description: |
Present only on limit rejections. Names the bound that was
exceeded, its configured value and the observed value, so a client
can tell which limit it hit without parsing prose.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: The configured value of the bound
observed:
type: integer
format: int64
description: The value observed when the request was rejected
unit:
type: string
description: Unit of `limit` and `observed`
examples:
- operations
bound:
type: string
description: Identifier of the bound that was exceeded
examples:
- account_concurrency_tts
```
**Examples:**
```yaml
deadline_exceeded:
value:
error: TTS synthesis deadline exceeded
code: TTS_DEADLINE_EXCEEDED
detail: TTS synthesis deadline exceeded
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## Next steps
The direct HTTP response is an undelimited protocol capture, not recoverable raw PCM or WAV. Do not add a WAV header to it. For playable output, use the released Socket.IO SDK path and add a WAV header only after collecting the SDK’s final decoded PCM payload.
### [Create a WAV file](/en/recipes/text-to-speech-to-file)
Run the tested SDK `0.18.0` recipe and convert the completed PCM16 output.
### [Understand the HTTP capture](/en/api-guides/realtime-http)
Review the missing frame delimiter, incomplete-output, deadline, and cleanup constraints.
### [Implement SDK TTS](/en/api-guides/socketio)
Use the released Socket.IO transport for a supported streaming lifecycle.
---
# مرجع API المباشرة عبر HTTP
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference
استخدم هذا المرجع عندما تحتاج إلى مسارات HTTP الدقيقة، أو المعاملات، أو أجسام الطلب، أو أشكال الاستجابة، أو أمثلة الطلبات المولّدة. لاتباع تكامل موجّه باستخدام SDK بالإصدار `0.18.0`، ابدأ من [البدء السريع](/ar/quickstart) أو [أدلة API](/ar/api-guides).
## اختر حسب دورة حياة الإدخال
| سير العمل | حالة الإدخال | الاستخدام الأنسب |
| --- | --- | --- |
| النسخ الدفعي Batch | تسجيل طويل ومكتمل | الاجتماعات والبودكاست والمقابلات والأرشيفات التي تُعالج كأعمال غير متزامنة |
| النسخ السريع Fast | وحدة صوت مكتملة ومحدودة | أدوار الوكلاء الحساسة للزمن والأوامر الصوتية والعبارات الحوارية القصيرة |
| ASR الفوري | الصوت ما زال يصل | الميكروفونات والمكالمات والتدفقات التي تحتاج إلى نتائج جزئية ونهائية |
| تحويل النص إلى كلام | الإدخال نص والإخراج صوت | إنشاء تدفق صوت `PCM16` من النص |
## اضبط الوصول
احصل على مفتاح API عبر مسار الوصول المعتمد في مؤسستك. احتفظ بالمفتاح في خادم موثوق، واستخدم المضيف ومسار الخدمة المهيأين لبيئتك. راجع [المصادقة](/ar/authentication) قبل إتاحة التكامل للمستخدمين.
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
| API | المسار الأساسي |
| --- | --- |
| Batch API | `/v1` |
| Realtime HTTP API | `/realtime` |
## أرسل طلبًا آمنًا
يوفر استعلام للقراءة فقط عن معرّف عمل غير موجود عمدًا دليلاً تشخيصيًا غير معدّل للحالة من دون إنشاء عمل:
```bash
curl --include "$API_URL/v1/transcribe/00000000-0000-4000-8000-000000000000" \
--header "x-api-key: $API_KEY" \
--header "Origin: $API_URL"
```
- يتوافق `404` مع البحث عن العمل غير الموجود، لكنه لا يثبت وحده صلاحية بيانات الاعتماد وقدرة Batch.
- يشير `401` إلى أن المفتاح مفقود أو غير صالح لمسار الطلب.
- يشير `403` إلى رفض الوصول؛ تحقق من القيم المهيأة عبر مسار الوصول المعتمد في مؤسستك.
## أقسام المرجع
### [Batch API](/ar/api-reference/batch)
أرسل تسجيلات طويلة ومكتملة، ثم استعلم عن المهمة حتى يصل إلى حالة نهائية.
### [Realtime HTTP API](/ar/api-reference/realtime-http)
استخدم HTTP المتدفق للنسخ السريع أو ASR الحي أو تمييز المتحدثين أو TTS.
## الحدود التشغيلية
- قد يعيد إرسال عمل Batch الحالة `429` عند نفاد سعة معالجة الصوت. تعامل معها كضغط سعة واستخدم بيانات السعة المعادة عند توفرها.
- لا تعد محاولة رفع ملف ذي نتيجة ملتبسة بلا تحقق. سجّل نتيجة الطلب في طبقة الأعمال حتى لا ينشئ انقضاء المهلة أعمالًا مكررة من دون ملاحظة.
- استخدم استعلامًا محدودًا لأعمال Batch وتوقف عند `done` أو `failed` أو `cleared`.
- تختلف قواعد التأطير ودورة الحياة بين HTTP وSocket.IO. اتبع صفحة وسيلة النقل التي تستخدمها فعلًا.
## الوصول عبر Markdown وLLM
- استخدم [`/ar/api-reference/md`](/ar/api-reference/md) لقراءة هذه الصفحة بصيغة Markdown الخام.
- ألحق مسار عملية، مثل [`/ar/api-reference/md/batch/submit-transcription-job`](/ar/api-reference/md/batch/submit-transcription-job)، لقراءة عملية واحدة.
- استخدم [`/llms-full.txt`](/llms-full.txt) لحزمة الوثائق الثنائية اللغة كاملة.
## الخطوات التالية
### [المصادقة](/ar/authentication)
احصل على مفتاح API واضبطه واحمه.
### [أدلة API](/ar/api-guides)
اختر بروتوكولًا واتبع دورة حياته.
### [الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits)
صنّف الإخفاقات ونفّذ إعادة المحاولة بأمان.
---
# جلب حالة عمل النسخ أو نتيجته (V1 القديم)
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/batch/get-transcription-job-legacy
## العملية
**GET `/transcribe/{job_id}/{lang}`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/v1`
- **عنوان URL للطلب:** `https://api.voice.humain.com/v1/transcribe/{job_id}/{lang}`
## الوصف
هذه عملية V1 للتوافق فقط، وتستخدمها حزم SDK لـJavaScript وPython في
الإصدار `0.18.0`. استخدم `GET /transcribe/{job_id}` (V2) في تكاملات HTTP
المباشرة الجديدة.
استخدم `jobId` العائد من عملية الإرسال، واستعلم عن `status` مع مهلة لكل
طلب وموعد نهائي كلي محدود. استمر فقط عند `queued` و`processing`، وتوقف عند
`done` أو `failed` أو `cleared`. اقرأ `results.transcript` و
`results.offsets` فقط عند `done`. لا تتضمن استجابة V1 ذات الحالة
`failed` سبب فشل قابلاً للقراءة آليًا، وتعني `cleared` أن حقول النتيجة
المخزنة غير متاحة. تعود حالات المهمة الخمس كلها ضمن HTTP `200`؛ وتشير
الاستجابات غير 2xx إلى خطأ في الطلب أو المصادقة أو التفويض أو البحث أو الخادم.
قد يكون تسليم `done` أو `failed` أحادي الاستهلاك مع القيمة الافتراضية
`save_result=false`. اضبط `save_result=true` في كل استعلام عندما يجب جلب
الاستجابة النهائية مجددًا بعد فقدها. لا يحدد API مدة احتفاظ.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `x-api-key`
## المعاملات
### المعامل `job_id`
- **الموضع:** `path`
- **مطلوب:** نعم
- **النوع:** `string (uuid)`
معرّف عمل النسخ.
**المخطط:**
```yaml
type: string
format: uuid
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `lang`
- **الموضع:** `path`
- **مطلوب:** نعم
- **النوع:** `string`
مقطع توافق قديم مطلوب في المسار. لا يستخدم معالج V1 الحالي هذه القيمة ولا يتحقق منها. ترسل حزم SDK في الإصدار `0.18.0` لغة الإرسال. ينبغي لعملاء HTTP المباشرين الجدد استخدام `GET /transcribe/{job_id}`.
**المخطط:**
```yaml
type: string
minLength: 1
examples:
- en
```
**الأمثلة:**
```yaml
- en
```
### المعامل `save_result`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `boolean`
اترك حقول النتيجة النهائية المخزنة متاحة بعد هذه القراءة. قد تجعل القيمة الافتراضية `false` تسليم `done` أو `failed` أحادي الاستهلاك. اضبط `true` في كل استعلام عندما يجب إعادة محاولة تسليم النتيجة النهائية. لا يحدد هذا الخيار مدة احتفاظ.
**المخطط:**
```yaml
type: boolean
default: false
```
**الأمثلة:**
```yaml
default:
value: true
```
### المعامل `diarization_force_align`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `boolean`
يتحكم فقط في `results.offsets[].speaker` ولا يغير `diarization_segments`. مع `true` (الافتراضي)، تُسند الكلمة التي يقع `startTime` لها خارج كل المقاطع الحقيقية إلى متحدث أقرب حد مقطع، استنادًا إلى منتصف الكلمة، ويُختار المقطع الأسبق عند التعادل. مع `false` تستخدم تلك الكلمات `UNKNOWN_SPEAKER`. وإذا لم توجد مقاطع حقيقية فتبقى `speaker` بقيمة `null`. لا تعرض حزم SDK في الإصدار `0.18.0` هذا الخيار. القيم المقبولة true/false أو 1/0.
**المخطط:**
```yaml
type: boolean
default: true
```
**الأمثلة:**
لا توجد قيمة موثقة.
## جسم الطلب
لا توجد قيمة موثقة.
## الاستجابات
### الاستجابة `200`
استجابة النسخ القديمة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- status
- APIVersion
- version
- metadata
- results
- diarization_segments
properties:
status:
type: string
enum:
- queued
- processing
- done
- failed
- cleared
description: |-
حالة المهمة:
- `queued`: ينتظر العمل المعالجة
- `processing`: يجري نسخ العمل حاليًا
- `done`: اكتمل النسخ بنجاح
- `failed`: فشل النسخ
- `cleared`: حقول النتيجة المخزنة غير متاحة؛ أوقف الاستعلام. لا تحدد هذه الحالة ضمانًا لحذف الوسائط أو مدة الاحتفاظ
APIVersion:
type: string
enum:
- v1
examples:
- v1
version:
type: string
enum:
- api-version
examples:
- api-version
metadata:
type: object
required:
- sautechVersion
- jobId
- fileDuration
properties:
sautechVersion:
type: string
enum:
- v1
examples:
- v1
jobId:
type: string
format: uuid
fileDuration:
type: number
format: float
results:
type: object
required:
- transcript
properties:
transcript:
type: string
offsets:
type: array
items:
type: object
required:
- word
- startTime
- endTime
properties:
word:
type: string
startTime:
type: number
format: float
endTime:
type: number
format: float
speaker:
type:
- string
- "null"
diarization_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
speaker:
type:
- string
- "null"
```
**الأمثلة:**
```yaml
queued:
summary: عمل في قائمة الانتظار
value:
status: queued
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: null
processing:
summary: عمل قيد المعالجة
value:
status: processing
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: null
done:
summary: عمل مكتمل
value:
status: done
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: hello world
offsets:
- word: hello
startTime: 0
endTime: 0.45
speaker: speaker-1
- word: world
startTime: 0.46
endTime: 0.9
speaker: null
diarization_segments:
- start_time: 0
end_time: 1
speaker: speaker-1
failed:
summary: عمل فاشل
value:
status: failed
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: null
cleared:
summary: حقول النتيجة المخزنة غير متاحة
value:
status: cleared
APIVersion: v1
version: api-version
metadata:
sautechVersion: v1
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
fileDuration: 12.34
results:
transcript: ""
diarization_segments: []
```
### الاستجابة `400`
معرّف عمل أو قيمة `save_result` أو `diarization_force_align` غير صالحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
invalid_job_id:
summary: معرّف عمل غير صالح
value:
error: error.uuid.invalid
code: VALIDATION_INVALID_UUID
detail: error.uuid.invalid
job_id: not-a-uuid
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_save_result:
summary: قيمة `save_result` غير صالحة
value:
error: error.api.error.param.save_result.invalid
code: VALIDATION_INVALID_PARAM
detail: error.api.error.param.save_result.invalid
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_force_align:
summary: قيمة `diarization_force_align` غير صالحة
value:
error: error.api.error.param.diarization_force_align.invalid
code: VALIDATION_INVALID_PARAM
detail: error.api.error.param.diarization_force_align.invalid
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
missing_key:
value:
error: auth.unauthorized
message: unauthorized
code: AUTH_UNAUTHORIZED
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى النسخ الدفعي
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: error.api_key.scope_denied
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `404`
عمل النسخ غير موجود
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
missing_job:
value:
error: error.transcription_job.get
code: TRANSCRIPTION_JOB_NOT_FOUND
detail: transcription job not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `500`
فشل استعلام النتيجة القديمة أو مسح النتيجة بعد الاستجابة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
lookup_failed:
value:
error: error.transcription_job.get
code: SERVER_INTERNAL
detail: error.transcription_job.get
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
clear_failed:
value:
error: error.transcription_job.clear_result_failed
code: SERVER_INTERNAL
detail: error.transcription_job.clear_result_failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
invalid_save_result:
summary: قيمة `save_result` غير صالحة
value:
error: error.api.error.param.save_result.invalid
code: VALIDATION_INVALID_PARAM
detail: error.api.error.param.save_result.invalid
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
أبقِ V1 فقط عندما يتطلبه التوافق مع SDK بالإصدار `0.18.0`. لعميل HTTP مباشر جديد، انتقل إلى V2؛ وفي الحالتين أوقف الاستعلام عند `done` أو `failed` أو `cleared`.
### [انقل HTTP المباشرة إلى V2](/ar/api-reference/batch/get-transcription-job)
استخدم عقد الحالة والنتيجة الموصى به لتكاملات HTTP الجديدة.
### [استخدم SDK المنشورة بأمان](/ar/recipes/transcribe-a-recording)
اتبع وصفة `0.18.0` المختبرة التي ما زالت تستهلك شكل V1.
### [حدّ إعادة المحاولة والاستعلام](/ar/api-guides/errors-and-rate-limits)
افصل حالات المهمة النهائية عن إخفاقات النقل وAPI.
---
# جلب حالة عمل النسخ أو نتيجته (V2)
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/batch/get-transcription-job
## العملية
**GET `/transcribe/{job_id}`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/v1`
- **عنوان URL للطلب:** `https://api.voice.humain.com/v1/transcribe/{job_id}`
## الوصف
هذه عملية الحالة والنتيجة الموصى بها للتكاملات المباشرة الجديدة عبر HTTP.
استخدم `jobId` الذي أعادته العملية `POST /transcribe/{lang}` بوصفه
`job_id`، واستدعِ العملية من خلفية موثوقة، وأرسل `x-api-key`.
تعيد القراءة الناجحة الغلاف `{ "message": "success", "data": ... }`.
استعلم عن `data.status` بمهلة لكل طلب ومهلة كلية محدودة للتطبيق. استمر فقط
عند `queued` أو `processing`، وتوقف عند `done` أو `failed` أو
`cleared`. استخدم `data.final_result` وحقول النتيجة المرتبطة فقط عند
`done`. الحالة `cleared` طرفية وتعني أن النتيجة غير متاحة.
شكل V2 مخصص للتكاملات المباشرة عبر HTTP. تستخدم حزم JavaScript وPython عند
الإصدار `0.18.0` مسار نتيجة V1 القديم وشكل استجابته.
مع القيمة الافتراضية `save_result=false`، قد تمسح القراءة الناجحة لعمل حالته
`done` أو `failed` حقول النتيجة المخزنة بعد بناء الاستجابة. وقد تعيد قراءة
لاحقة الحالة `cleared`. عيّن `save_result=true` عندما يجب أن يكون جلب
النتيجة النهائية قابلاً للتكرار. لا يحدد API مدة احتفاظ.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `x-api-key`
## المعاملات
### المعامل `job_id`
- **الموضع:** `path`
- **مطلوب:** نعم
- **النوع:** `string (uuid)`
معرّف عمل النسخ.
**المخطط:**
```yaml
type: string
format: uuid
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `save_result`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `boolean`
احتفظ بحقول النتيجة النهائية بعد هذه القراءة. القيمة الافتراضية `false`.
مع `false`، قد تمسح قراءة `done` أو `failed` حقول النتيجة بعد إعادتها،
وقد تعيد قراءة لاحقة الحالة `cleared`. عيّن `true` قبل الاستعلام عندما
يحتاج التطبيق إلى إعادة محاولة جلب النتيجة النهائية أو جلبها مجددًا. لا يحدد
هذا الخيار مدة احتفاظ.
**المخطط:**
```yaml
type: boolean
default: false
```
**الأمثلة:**
لا توجد قيمة موثقة.
## جسم الطلب
لا توجد قيمة موثقة.
## الاستجابات
### الاستجابة `200`
عمل النسخ
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- message
- data
properties:
message:
type: string
enum:
- success
examples:
- success
data:
type: object
required:
- id
- version
- created_at
- updated_at
- language
- audio_duration
- sample_rate_hz
- status
properties:
id:
type: string
format: uuid
version:
type: integer
format: int32
created_at:
type:
- string
- "null"
format: date-time
updated_at:
type:
- string
- "null"
format: date-time
language:
type: string
enum:
- en
- ar
- codeswitch
- auto
audio_duration:
type: number
format: float
sample_rate_hz:
type: integer
format: int32
description: معدل عينة الصوت المعالج بالهرتز.
examples:
- 16000
status:
type: string
enum:
- queued
- processing
- done
- failed
- cleared
description: |-
حالة المهمة:
- `queued`: ينتظر العمل المعالجة
- `processing`: يجري نسخ العمل حاليًا
- `done`: اكتمل النسخ بنجاح
- `failed`: فشل النسخ
- `cleared`: حقول النتيجة المخزنة غير متاحة؛ أوقف الاستعلام. لا تحدد هذه الحالة ضمانًا لحذف الوسائط أو مدة الاحتفاظ
asr_result:
type:
- string
- "null"
asr_word_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
diarization_segments:
type:
- array
- "null"
description: نطاقات زمن المتحدثين المعادة منفصلة عن توقيت الكلمات.
items:
type: object
required:
- start_time
- end_time
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
speaker:
type:
- string
- "null"
itn_result:
type:
- string
- "null"
itn_word_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
itn_output_formats:
type:
- string
- "null"
redaction_result:
type:
- string
- "null"
redaction_word_segments:
type:
- array
- "null"
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
redaction_labels:
type:
- string
- "null"
final_result:
type:
- string
- "null"
description: النص النهائي المتاح عندما تكون `status` بالقيمة `done`.
final_word_segments:
type:
- array
- "null"
description: توقيت الكلمات النهائي. لا تتضمن هذه الكائنات تسميات المتحدثين.
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
```
**الأمثلة:**
```yaml
queued:
summary: عمل في قائمة الانتظار
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:00.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: queued
processing:
summary: عمل قيد المعالجة
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:02.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: processing
done:
summary: عمل مكتمل
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:05.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: done
asr_result: hello world
asr_word_segments:
- start_time: 0
end_time: 0.45
word: hello
diarization_segments:
- start_time: 0
end_time: 1
speaker: speaker-1
itn_result: null
itn_word_segments: null
itn_output_formats: null
redaction_result: null
redaction_word_segments: null
redaction_labels: ""
final_result: hello world
final_word_segments:
- start_time: 0
end_time: 0.45
word: hello
failed:
summary: عمل فاشل
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:05.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: failed
cleared:
summary: مُسحت النتيجة المخزنة
value:
message: success
data:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
version: 1
created_at: 2025-12-29T08:00:00.000Z
updated_at: 2025-12-29T08:00:06.000Z
language: en
audio_duration: 12.34
sample_rate_hz: 16000
status: cleared
```
### الاستجابة `400`
معرّف عمل أو قيمة `save_result` غير صالحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
invalid_job_id:
summary: معرّف عمل غير صالح
value:
error: error.uuid.invalid
code: VALIDATION_INVALID_UUID
detail: error.uuid.invalid
job_id: not-a-uuid
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
missing_key:
value:
error: auth.unauthorized
message: unauthorized
code: AUTH_UNAUTHORIZED
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى النسخ الدفعي
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: error.api_key.scope_denied
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `404`
عمل النسخ غير موجود
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
missing_job:
value:
error: error.transcription_job.get
code: TRANSCRIPTION_JOB_NOT_FOUND
detail: transcription job not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `500`
خطأ داخلي في الخادم
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
internal:
value:
error: error.transcription_job.get
code: SERVER_INTERNAL
detail: error.transcription_job.get
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
حوّل هذا الاستعلام إلى حلقة محدودة: واصل فقط عند `queued` و`processing`، وتوقف عند كل حالة نهائية، واضبط `save_result=true` عندما يجب استرجاع استجابة نهائية مفقودة مرة أخرى.
### [نفّذ استعلامًا محدودًا](/ar/api-guides/batch-rest)
أضف مهلة لكل طلب وموعدًا نهائيًا كليًا وتعاملًا كاملًا مع الحالات النهائية.
### [شغّل سير عمل SDK](/ar/recipes/transcribe-a-recording)
استخدم وصفة تسجيل مختبرة لـSDK JavaScript أو Python بالإصدار `0.18.0`.
### [تعامل مع إخفاقات الاستعلام](/ar/api-guides/errors-and-rate-limits)
صنّف استجابات المصادقة وعدم العثور وحد المعدل والخادم.
---
# Batch API
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/batch
اختر Batch عندما يكون التسجيل كاملًا والعمل طويلًا: اجتماع أو بودكاست أو مقابلة أو مكالمة أو أرشيف. ارفع الملف مرة واحدة، واحفظ معرّف المهمة المعاد، ثم اجلب النتيجة بصورة غير متزامنة.
> **HTTP المباشرة V2 وSDK بالإصدار 0.18.0**
>
> لتكامل HTTP مباشر جديد، فضّل `GET /v1/transcribe/{job_id}` واستجابة V2. تستخدم أداتا JavaScript وPython بالإصدار `0.18.0` حاليًا مسار V1 القديم عند الاستعلام، لذلك احتفظ بشكل استجابته عند استخدام دوال SDK المنشورة.
## دورة حياة العمل
1. أرسل ملفًا صوتيًا كاملًا واحدًا وسجّل `jobId` المعاد قبل تنفيذ أي عمل آخر.
2. قبل الاستعلام، اضبط `save_result=true` عندما يجب استرجاع الاستجابة النهائية مجددًا بعد فقدها؛ ثم استخدم فاصلًا محدودًا وموعدًا نهائيًا كليًا وتفاوتًا عشوائيًا عند مشاركة السعة.
3. واصل الاستعلام ما دامت الحالة `queued` أو `processing`.
4. توقف عند كل حالة نهائية: استخدم ناتج `done`، واعرض `failed`، وتعامل مع `cleared` كناتج لم يعد متاحًا.
## نقاط النهاية
### [POST · إرسال مهمة نسخ](/ar/api-reference/batch/submit-transcription-job)
ارفع الصوت، واختر اللغة وخيارات المعالجة، واستلم معرّف المهمة.
### [GET · جلب عمل (V2)](/ar/api-reference/batch/get-transcription-job)
الاستعلام الموصى به لتكامل HTTP المباشر مع غلاف النجاح القياسي.
### [GET · جلب عمل (V1 القديم)](/ar/api-reference/batch/get-transcription-job-legacy)
الاستجابة القديمة التي تستخدمها دوال SDK في JavaScript وPython بالإصدار `0.18.0`.
## تعامل مع كل حالة نهائية
| الحالة | المعنى | إجراء العميل |
| --- | --- | --- |
| `queued` | في انتظار المعالجة | واصل الاستعلام ضمن الموعد النهائي |
| `processing` | النسخ قيد التنفيذ | واصل الاستعلام ضمن الموعد النهائي |
| `done` | الناتج جاهز | تحقق من النتيجة التي تحتاجها واحفظها |
| `failed` | فشلت المعالجة | أوقف الاستعلام واعرض الإخفاق |
| `cleared` | مُسح الناتج المخزن | أوقف الاستعلام ولا تنتظر نتيجة لاحقة |
## ملاحظات الإنتاج
- قد يعيد الإرسال `429` مع سعة الصوت المتبقية بالثواني. تراجع وحدّ إعادة المحاولة بدل إعادة الإرسال فورًا.
- يكون انقضاء المهلة بعد الرفع ملتبسًا: قد تقبل الخدمة الملف حتى إن لم يتلق العميل الاستجابة. تتبع المحاولات وطابقها قبل إعادة المحاولة.
- اضبط مهلة لكل طلب وموعدًا نهائيًا كليًا للاستعلام. لا تسمح للـAPI أو حلقة SDK بالانتظار إلى الأبد.
- قد تمسح القيمة الافتراضية `save_result=false` الحقول المخزنة بعد بناء استجابة `done` أو `failed`. استخدم `true` للتسليم القابل للتكرار، لكن لا تستنتج مدة احتفاظ.
- استخدم Fast لعبارة حوارية واحدة، محدودة ومكتملة. أبقِ التسجيلات الطويلة على Batch.
## الخطوات التالية
### [دليل Batch REST](/ar/api-guides/batch-rest)
ابنِ دورة حياة HTTP المباشرة كاملة.
### [نسخ تسجيل](/ar/recipes/transcribe-a-recording)
شغّل مثال SDK مختبرًا للإصدار `0.18.0`.
### [الأخطاء وحدود المعدل](/ar/api-guides/errors-and-rate-limits)
اجعل الاستعلام وإعادة المحاولة آمنين.
---
# إرسال مهمة نسخ
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/batch/submit-transcription-job
## العملية
**POST `/transcribe/{lang}`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/v1`
- **عنوان URL للطلب:** `https://api.voice.humain.com/v1/transcribe/{lang}`
## الوصف
أرسل تسجيلًا مكتملًا واحدًا للنسخ غير المتزامن عبر Batch. استخدم Batch
للوسائط الطويلة أو الكبيرة المكتملة، وFast لوحدة حوارية واحدة مكتملة
ومحدودة وحساسة لزمن الاستجابة، وRealtime فقط ما دام الصوت يصل.
تعني استجابة `200` أن المهمة قُبلت بحالة `queued`، لا أن النسخ اكتمل. خزّن
`jobId` ثم استعلم من `GET /transcribe/{job_id}` حتى `done` أو `failed`
أو `cleared`.
لا تدعم هذه العملية عقد مفتاح idempotency. فلا تعد رفعًا عشوائيًا بعد مهلة أو
انقطاع اتصال أو استجابة `5xx`؛ فقد تكون المهمة موجودة بالفعل وقد تنشئ
الإعادة عملاً مكررًا. تمثل استجابة `429` ضغط سعة، وتكون `data.capacity`
سعة معالجة الصوت المتبقية بالثواني عند توفر الرصيد، وليست مدة انتظار أو وقت
إعادة ضبط.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `x-api-key`
## المعاملات
### المعامل `lang`
- **الموضع:** `path`
- **مطلوب:** نعم
- **النوع:** `string`
رمز لغة النسخ.
**المخطط:**
```yaml
type: string
enum:
- en
- ar
- codeswitch
- auto
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `asr`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
مفتاح دقيق اختياري لنموذج ASR. عند حذفه تستخدم الخدمة النموذج الافتراضي
المضبوط لقيمة `lang` المختارة. يعيد المفتاح غير المعروف أو غياب النموذج
الافتراضي الحالة `400` والرمز `ASR_MODEL_NOT_FOUND`.
**المخطط:**
```yaml
type: string
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `diarization`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
محدد تمييز المتحدثين:
- الحذف أو `0` أو `false`: معطل
- `1` أو `true`: مفعّل بالنموذج الافتراضي
- `d1`: تمييز المتحدثين
- `d2`: تمييز المتحدثين بالنموذج البديل
**المخطط:**
```yaml
type: string
enum:
- "0"
- "1"
- "false"
- "true"
- d1
- d2
```
**الأمثلة:**
```yaml
enable:
value: "1"
disable:
value: "0"
enable_boolean:
value: "true"
disable_boolean:
value: "false"
d1:
value: d1
d2:
value: d2
```
### المعامل `itn`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
محدد تطبيع النص العكسي (ITN):
- الحذف أو `0` أو `false`: معطل
- `1` أو `true`: مفعّل؛ يحول الصيغ المنطوقة إلى مكتوبة، مثل twenty five إلى 25
**المخطط:**
```yaml
type: string
enum:
- "0"
- "1"
- "false"
- "true"
```
**الأمثلة:**
```yaml
enable:
value: "1"
disable:
value: "0"
enable_boolean:
value: "true"
disable_boolean:
value: "false"
```
### المعامل `redact`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
محدد تنقيح معلومات PII:
- الحذف أو `0` أو `false`: معطل
- `1` أو `true`: مفعّل؛ يحجب المعلومات الحساسة في النصوص
**المخطط:**
```yaml
type: string
enum:
- "0"
- "1"
- "false"
- "true"
```
**الأمثلة:**
```yaml
enable:
value: "1"
disable:
value: "0"
enable_boolean:
value: "true"
disable_boolean:
value: "false"
```
## جسم الطلب
- **مطلوب:** نعم
#### نوع المحتوى: `multipart/form-data`
**المخطط:**
```yaml
type: object
required:
- file
properties:
file:
type: string
description: |-
تسجيل صوتي مكتمل واحد، وهو الجزء الصوتي الوحيد المقبول. يعيد الإدخال غير
المدعوم أو التالف أو الفارغ أو صفري المدة الحالة `422`. ويعيد التسجيل الأطول من
حد المدة بعد فك الترميز الحالة `422` `AUDIO_DURATION_EXCEEDED`؛ ويعيد جزء صوتي
ثانٍ الحالة `422` `FILE_COUNT_EXCEEDED`. راجع «حدود الطلب».
contentMediaType: application/octet-stream
```
**الأمثلة:**
لا توجد قيمة موثقة.
## الاستجابات
### الاستجابة `200`
قُبلت المهمة ووُضعت في قائمة المعالجة غير المتزامنة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- jobId
- status
properties:
jobId:
type: string
format: uuid
status:
type: string
enum:
- queued
examples:
- queued
```
**الأمثلة:**
```yaml
queued:
value:
jobId: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
status: queued
```
### الاستجابة `400`
لغة أو نموذج أو نوع محتوى أو جسم multipart أو حقل ملف غير صالح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
invalid_language:
summary: لغة غير صالحة
value:
error: error.language.invalid
code: VALIDATION_INVALID_LANGUAGE
detail: error.language.invalid
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_content_type:
summary: الطلب ليس بيانات نموذج multipart
value:
error: error.api.error.request.invalid_format
code: VALIDATION_INVALID_FORMAT
detail: error.api.error.request.invalid_format
retryable: false
timestamp: 2026-01-15T10:30:00Z
missing_file:
summary: حقل multipart الأول ليس file
value:
error: error.api.error.multipart.file.missing
code: VALIDATION_REQUIRED_FIELD
detail: error.api.error.multipart.file.missing
retryable: false
timestamp: 2026-01-15T10:30:00Z
unknown_asr_model:
summary: نموذج ASR غير مضبوط
value:
error: error.asr_model.not_found
code: ASR_MODEL_NOT_FOUND
detail: error.asr_model.not_found
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
missing_key:
value:
error: auth.unauthorized
message: unauthorized
code: AUTH_UNAUTHORIZED
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى النسخ الدفعي
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: error.api_key.scope_denied
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `413`
تجاوز الطلب حد البايتات. لم تُنشأ أي مهمة ولم يبدأ أي نسخ. ويكون
`data.observed` هو `Content-Length` المعلن من العميل عندما يتجاوز الحد أصلًا؛
أما عندما يُرفض الجسم أثناء قراءته فهو `limit + 1`، وهو أصغر حجم يمكن إثباته،
لأن القراءة تتوقف عند تلك النقطة.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
declared_too_large:
summary: "`Content-Length` يتجاوز الحد أصلًا"
value:
error: error.api.error.request.too_large
code: PAYLOAD_TOO_LARGE
detail: error.api.error.request.too_large
retryable: false
timestamp: 2026-01-15T10:30:00Z
request_id: 4bf92f3577b34da6a3ce929d0e0e4736
data:
limit: 536870912
observed: 1073741824
unit: bytes
bound: request_bytes
unvalidatable_tail:
summary: بيانات بعد التسجيل أكثر من أن يكتمل فحص الحدود
value:
error: error.api.error.request.unvalidatable_tail
code: PAYLOAD_TOO_LARGE
detail: error.api.error.request.unvalidatable_tail
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 524288
observed: 524289
unit: bytes
bound: unvalidatable_tail_bytes
overran_while_reading:
summary: تجاوز الجسم الحد في أثناء البث
value:
error: error.api.error.request.too_large
code: PAYLOAD_TOO_LARGE
detail: error.api.error.request.too_large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 536870912
observed: 536870913
unit: bytes
bound: request_bytes
```
### الاستجابة `422`
إدخال صوتي غير مدعوم أو تالف، أو طلب صالح يتجاوز عبؤه حدًا دلاليًا. لم
تُنشأ أي مهمة ولم يبدأ أي نسخ؛ راجع «حدود الطلب» لمعرفة الحالات التي يُحوَّل فيها
الصوت قبل الرفض.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
unsupported_audio:
value:
error: unsupported or corrupt audio input for conversion
code: VALIDATION_FILE_CORRUPT
detail: unsupported or corrupt audio input for conversion
retryable: false
timestamp: 2026-01-15T10:30:00Z
audio_too_long:
summary: الصوت بعد فك الترميز يتجاوز حد المدة
value:
error: error.api.error.audio.duration_exceeded
code: AUDIO_DURATION_EXCEEDED
detail: error.api.error.audio.duration_exceeded
retryable: false
timestamp: 2026-01-15T10:30:00Z
request_id: 4bf92f3577b34da6a3ce929d0e0e4736
data:
limit: 14400
observed: 21600
unit: seconds
bound: audio_duration
too_many_files:
summary: أُرسل أكثر من جزء صوتي واحد
value:
error: error.api.error.multipart.file.count_exceeded
code: FILE_COUNT_EXCEEDED
detail: error.api.error.multipart.file.count_exceeded
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1
observed: 2
unit: files
bound: file_parts
too_many_parts:
summary: أجزاء multipart أكثر مما يسمح به الطلب
value:
error: error.api.error.multipart.part.count_exceeded
code: FILE_COUNT_EXCEEDED
detail: error.api.error.multipart.part.count_exceeded
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 8
observed: 9
unit: parts
bound: multipart_parts
```
### الاستجابة `429`
نفدت سعة معالجة الصوت. تمثل `data.capacity` ثواني الصوت المتبقية عند توفر رصيد؛ وليست مدة إعادة محاولة أو وقت إعادة ضبط أو ضمان حصة. قد تعني القيمة صفر عدم توفر رصيد.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
- data
properties:
error:
type: string
code:
type: string
enum:
- RATE_LIMIT_EXCEEDED
detail:
type: string
retryable:
type: boolean
timestamp:
type: string
format: date-time
data:
type: object
required:
- capacity
properties:
capacity:
type: number
format: float
description: سعة معالجة الصوت المتبقية بالثواني عند توفر رصيد. ليست مدة إعادة محاولة أو وقت إعادة ضبط؛ وقد تعني القيمة صفر عدم توفر رصيد.
```
**الأمثلة:**
```yaml
limited:
value:
error: error.rate_limit
code: RATE_LIMIT_EXCEEDED
detail: error.rate_limit
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
capacity: 120.5
```
### الاستجابة `500`
فشل الإرسال؛ وقد تكون النتيجة ملتبسة بعد إنشاء المهمة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي تصدرها هذه الخدمة
في جسم `ErrorResponse`. أما استجابة حد المعدل `429` فتستخدم
`RateLimitErrorResponse` وتحمل `RATE_LIMIT_EXCEEDED` بدلًا من ذلك.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- FILE_COUNT_EXCEEDED
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- SERVER_INTERNAL
- TRANSCRIPTION_JOB_NOT_FOUND
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
description: معرّف المهمة الذي أرسله العميل. قد يكون UUID صالحًا لأخطاء ما بعد الإنشاء أو القيمة غير الصالحة المرسلة عندما تكون `code` بالقيمة `VALIDATION_INVALID_UUID`.
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
request_id:
type: string
description: |-
معرّف التتبع لهذا الطلب، للربط في طلب الدعم. موجود في حالات رفض حدود
الطلب؛ وغائب عندما لا يكون التتبع مسجِّلًا.
data:
allOf:
- type: object
required:
- limit
- observed
- unit
- bound
description: الحد الذي تم تجاوزه وقيمته المضبوطة وما تم رصده.
properties:
limit:
type: integer
format: int64
description: القيمة العليا المضبوطة، بوحدة `unit`.
observed:
type: integer
format: int64
description: |-
القيمة المرصودة، بوحدة `unit`. وهي أكبر من `limit` دائمًا. وتُقرَّب
المدد إلى الأعلى، لذلك يبلّغ التسجيل الذي يزيد على السقف بجزء من الثانية عن قيمة
أعلى منه.
unit:
type: string
enum:
- bytes
- seconds
- files
- parts
bound:
type: string
description: أي حد تم تجاوزه.
enum:
- request_bytes
- audio_duration
- file_parts
- multipart_parts
- unvalidatable_tail_bytes
description: |-
موجود فقط في حالة رفض لحد من حدود الطلب (`PAYLOAD_TOO_LARGE` أو
`AUDIO_DURATION_EXCEEDED` أو `FILE_COUNT_EXCEEDED`). وغائب فيما عدا ذلك.
```
**الأمثلة:**
```yaml
transcription_failed:
value:
error: error.api.transcription
code: ASR_TRANSCRIPTION_FAILED
detail: error.api.transcription
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
بعد أن يعيد الطلب `jobId`، خزّنه قبل مغادرة معالج الطلب. ثم استعلم عبر V2 بموعد نهائي محدود حتى تصل المهمة إلى `done` أو `failed` أو `cleared`.
### [استعلم عن المهمة عبر V2](/ar/api-reference/batch/get-transcription-job)
اقرأ شكل الحالة والنتيجة الموصى به لتكامل HTTP المباشر.
### [ابنِ دورة حياة Batch](/ar/api-guides/batch-rest)
اربط الإرسال والاستعلام المحدود والتعامل مع الحالات النهائية.
### [خطط للتعامل الآمن مع الإخفاقات](/ar/api-guides/errors-and-rate-limits)
تعامل مع ضغط السعة ونتائج الرفع الملتبسة من دون إعادة محاولة عشوائية.
---
# بث النسخ السريع لوحدة صوت مكتملة
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/realtime-http/fast-transcription
## العملية
**POST `/http/stt`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/realtime`
- **عنوان URL للطلب:** `https://api.voice.humain.com/realtime/http/stt`
## الوصف
انسخ وحدة صوتية مكتملة ومحدودة وحساسة لزمن الاستجابة، مثل دور مستخدم
منتهٍ في محادثة وكيلية أو أمر صوتي. استخدم Batch للتسجيلات المكتملة الطويلة
أو الكبيرة، واستخدم ASR المباشر ما دام الصوت يصل.
هذه عملية مباشرة عبر HTTP. يستخدم عملاء Fast في SDK `0.18.0` بروتوكول
Socket.IO؛ ولا يستدعون هذا المسار. أرسل الطلب من خلفية موثوقة مع
`X-Api-Key` وقدرة ASR الفوري.
قدّم UUID فريدًا في `id` وملفًا صوتيًا مكتملًا واحدًا في حقل multipart
المسمى `file`. تتقدم `language` غير الفارغة على `lang`، وتتقدم `asr`
غير الفارغة على `model`. تستخدم اللغة المحذوفة أو `auto` والنموذج المحذوف
الإعدادات الافتراضية المضبوطة للبيئة. يطبق Fast اختيار اللغة ونموذج ASR فقط؛
استخدم Batch عند الحاجة إلى تمييز المتحدثين أو ITN أو التنقيح.
الاستجابة بصيغة NDJSON. قد يصدر الطلب سجلات نسخ جزئية قبل السجل النهائي. إذا
فشل استدعاء لاحق بعد إرسال الخرج، ينتهي بث `200` الجزئي من دون إلحاق خطأ
JSON. لا تعد العملية مكتملة إلا بعد ملاحظة `is_final: true` صراحة، وعامل
EOF أو الإلغاء أو انقضاء مهلة التطبيق من دون سجل نهائي على أنه عدم اكتمال.
`seq` بيانات تشخيصية مبهمة لا تضمن ترتيبًا ولا تفردًا.
## الحدود
ينطبق حدّان مستقلان، وهما يقيسان أمرين مختلفين.
يجب ألا يتجاوز جسم طلب multipart كاملًا **64 MiB** (`67108864` بايت). وتجاوزه
هو الحالة `413` برمز `PAYLOAD_TOO_LARGE` و`data.bound: fast_audio_bytes`.
ويجب ألا يزيد الصوت بعد فك الترميز على **1800 ثانية** (30 دقيقة). وتجاوزه هو
الحالة `422` برمز `AUDIO_DURATION_EXCEEDED` و
`data.bound: fast_audio_duration`. وهذا حد منفصل لأن رفعًا مضغوطًا صغيرًا قد
يُفك إلى ساعات كثيرة: فالطلب المقبول تمامًا بالبايتات قد يطلب مع ذلك عملًا
صوتيًا أكبر مما تؤديه هذه النقطة. والحدان شاملان — النجاح عند الحد بالضبط،
والفشل عند تجاوزه فقط.
وتفرض الخدمة حد المدة من ترويسة الحاوية حيث يعلن الملف طوله بنفسه، ومن بيانات
الحاوية الوصفية حيث يستطيع مفكك الترميز قراءتها، وإلا فأثناء فك الترميز مع
التوقف عند السقف. ولذلك يُرفض الصوت المفرط في الطول قبل أي استدلال، ولا يستهلك
أي رصيد من سعة الصوت. ويمكن للنشر تغيير الحدّين معًا عبر
`REALTIME_MAX_BODY_BYTES_FAST_TRANSCRIPTION` و
`REALTIME_MAX_FAST_AUDIO_DURATION_SEC`، ولذلك لا يعلن هذا المخطط قيمة
`maxLength` ثابتة.
وللتسجيلات الأطول من 30 دقيقة، أو الأكبر من 64 MiB، قسّم الصوت إلى وحدات أقصر
أو استخدم واجهة النسخ الدفعي التي يبلغ سقفها 4 ساعات لكل ملف.
## تنسيق الصوت
يجب أن تكون الحمولة AAC (ADTS) أو FLAC أو MP3 أو WAV أو ملف ISO base media.
ويتعرف الخادم على الحاوية من الحمولة نفسها، لا من اسم ملف ولا من نوع وسيط
أبدًا، ويُرفض أي شيء آخر بالحالة `400` وبالرمز `ASR_UNSUPPORTED_CODEC` حتى
عندما يكون قابلًا لفك الترميز.
ومدخل ISO base media عائلة: فصيغة MP4 هي الشكل المقصود والمدعوم، أما MOV وM4A
و3GP و3G2 وMJ2 فتشترك معها في مفكك حاويات واحد ولذلك يقبلها الفحص نفسه. وMP4
وحدها مختبرة ومقصودة؛ فلا تبنِ على غيرها. وضع الذرة `moov` في مقدمة الملف —
وهذه ليست سياسة يرفض الخادم على أساسها، بل مطلب عملي، لأن الرفع يُقرأ إلى
الأمام فقط ولا يمكن الوصول إلى `moov` في نهايته.
ومعدل العينات وعدد القنوات غير مقيدين: يُعاد تشكيل الصوت ويُدمج إلى قناة أحادية
عند معدل العينات المضبوط لنموذج ASR المختار، وهو معدل لا يختاره العميل.
طبّق مهلًا نهائية محدودة للاتصال وعدم النشاط والعملية كاملة. لا تدعم هذه
العملية عقد idempotency أو إعادة تشغيل؛ فلا تعد الإرسال عشوائيًا بعد مهلة أو
انقطاع ملتبس.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `X-Api-Key`
## المعاملات
### المعامل `id`
- **الموضع:** `query`
- **مطلوب:** نعم
- **النوع:** `string (uuid)`
UUID ارتباط جديد ينشئه العميل. وهو ليس مفتاح idempotency.
**المخطط:**
```yaml
type: string
format: uuid
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `language`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
لغة النسخ. يُقبل `lang` أيضًا اسمًا مستعارًا. تتقدم `language` غير
الفارغة على `lang`. تستخدم القيمة الفارغة أو `auto` الإعداد التلقائي
الافتراضي المضبوط للبيئة.
**المخطط:**
```yaml
type: string
enum:
- en
- ar
- codeswitch
- auto
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `asr`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
مفتاح دقيق اختياري لنموذج ASR؛ ويُقبل `model` أيضًا اسمًا مستعارًا.
تتقدم `asr` غير الفارغة. إذا حُذف الحقلان، تستخدم الخدمة الإعداد الافتراضي
المضبوط للغة المختارة.
**المخطط:**
```yaml
type: string
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `model`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
اسم مستعار لـ `asr`.
**المخطط:**
```yaml
type: string
```
**الأمثلة:**
لا توجد قيمة موثقة.
### المعامل `lang`
- **الموضع:** `query`
- **مطلوب:** لا
- **النوع:** `string`
اسم مستعار لا يُستخدم إلا عند حذف `language` أو كونها فارغة.
**المخطط:**
```yaml
type: string
enum:
- en
- ar
- codeswitch
- auto
```
**الأمثلة:**
لا توجد قيمة موثقة.
## جسم الطلب
- **مطلوب:** نعم
#### نوع المحتوى: `multipart/form-data`
**المخطط:**
```yaml
type: object
required:
- file
properties:
file:
type: string
description: وحدة صوتية مكتملة ومحدودة واحدة. يفك Fast ترميز الملف المرفوع قبل ASR.
contentMediaType: application/octet-stream
```
**الأمثلة:**
لا توجد قيمة موثقة.
## الاستجابات
### الاستجابة `200`
صفر أو أكثر من سجلات النسخ بصيغة NDJSON. بعد بدء الخرج، ينهي أي فشل لاحق
البثَّ الجزئي من دون إلحاق خطأ JSON. ويتطلب الاكتمال ملاحظة سجل يحتوي
`is_final: true`.
**الترويسات:**
```yaml
Cache-Control:
schema:
type: string
enum:
- no-store
description: يمنع الوسطاء من تخزين سجلات النص مؤقتًا.
```
#### نوع المحتوى: `application/x-ndjson`
**المخطط:**
```yaml
type: object
required:
- id
- seq
- transcription
- words
- is_final
properties:
id:
type: string
format: uuid
description: معرّف طلب النسخ.
seq:
type: integer
format: int64
description: قيمة تشخيصية مبهمة لا تضمن ترتيبًا ولا تفردًا.
transcription:
type: string
description: مقطع النص المنسوخ.
words:
type: array
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
description: نص الكلمة.
is_final:
type: boolean
description: تكون `true` للمقطع النهائي.
```
**الأمثلة:**
```yaml
partial:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello wor
words:
- start_time: 0
end_time: 0.45
word: hello
is_final: false
final:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello world
words:
- start_time: 0
end_time: 0.45
word: hello
- start_time: 0.46
end_time: 0.9
word: world
is_final: true
```
### الاستجابة `400`
معرّف طلب أو لغة أو رفع multipart أو حاوية صوت أو نموذج ASR غير صالح.
وكل حالة هنا قابلة للإصلاح من جهة العميل، لذلك لا يُبلَّغ عن أي منها أبدًا
كخطأ `5xx`.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
invalid_id:
summary: معرّف طلب غير صالح
value:
error: invalid request id
code: VALIDATION_INVALID_UUID
detail: invalid request id
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_language:
summary: لغة غير صالحة
value:
error: invalid language
code: VALIDATION_INVALID_LANGUAGE
detail: invalid language
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_file:
summary: رفع ملف multipart غير صالح
value:
error: invalid file upload
code: VALIDATION_FILE_CORRUPT
detail: invalid file upload
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
unsupported_container:
summary: حاوية الصوت خارج المجموعة المنشورة
description: |-
يجب أن تكون الحمولة AAC (ADTS) أو FLAC أو MP3 أو WAV أو ملف ISO base
media. وتُرفض حاوية كان مفكك الترميز يستطيع قراءتها لولا ذلك، فهذا قرار
تعاقدي وليس فشلًا في فك الترميز. أعد الترميز وأعد الإرسال؛ فالبايتات نفسها
لا يمكن أن تنجح. راجع «تنسيق الصوت» في العملية لمعرفة المجموعة المقبولة
بالضبط، ولمعرفة سبب كون موضع `moov` مطلبًا عمليًا لا شيئًا يرفض الخادم
على أساسه.
value:
error: audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV
code: ASR_UNSUPPORTED_CODEC
detail: audio container is not supported; use AAC, FLAC, MP3, MP4 or WAV
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
unknown_model:
summary: نموذج ASR غير مضبوط
value:
error: ASR model not found
code: ASR_MODEL_NOT_FOUND
detail: ASR model not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى قدرة الصوت المطلوبة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `405`
الطريقة غير مسموحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `413`
تجاوز جسم الطلب حد البايتات المضبوط لهذا المسار الصوتي: 64 MiB لرفع
Fast، و16 MiB لإطارات ASR الفوري، و16 MiB لإطارات تمييز المتحدثين الفوري. وهو
غير قابل لإعادة المحاولة بالحجم نفسه؛ أعد إرسال وحدة أو مقطع أصغر.
ويسمّي `data.bound` حد البايتات الذي تم بلوغه — `fast_audio_bytes` أو
`realtime_asr_frame_bytes` أو `realtime_diarization_frame_bytes`. و
`data.observed` هو حجم الطلب الدقيق عندما يعلن العميل `Content-Length`، وهو
فيما عدا ذلك حد أدنى (الحد زائد بايت واحد)، لأن الجسم الذي لا يعلن طوله يُقطع
في أثناء القراءة ولا يُعرف حجمه الحقيقي أبدًا.
ولا تُبلَغ هذه الحالة إلا من عدّ بايتات. أما الطلب المقبولة بايتاته والذي يطول
صوته بعد فك الترميز فهو الحالة `422` برمز `AUDIO_DURATION_EXCEEDED` بدلًا
منها.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
declared_length_over_the_cap:
summary: أُعلن `Content-Length`، فالقيمة المرصودة دقيقة
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 20971520
unit: bytes
bound: realtime_asr_frame_bytes
streamed_body_over_the_cap:
summary: لا طول معلن، فالقيمة المرصودة هي الحد زائد بايت واحد
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 67108864
observed: 67108865
unit: bytes
bound: fast_audio_bytes
```
### الاستجابة `422`
حُلِّل الطلب بصورة صحيحة وكانت بايتاته مقبولة، لكن مقدار الصوت الذي
يطلب من الخدمة معالجته يتجاوز سقف هذه النقطة (RFC 9110 15.5.21). ورفع مضغوط
صغير يُفك إلى ساعات كثيرة هو هذه الحالة بالضبط، ولهذا لا تكون الحالة `413`.
ويسمّي `data.bound` السقف الصوتي الذي تم بلوغه:
* `fast_audio_duration` — إرسال Fast واحد فُك إلى أكثر من 1800 ثانية. قسّم
التسجيل أو استخدم واجهة النسخ الدفعي.
* `session_audio_duration` — أرسلت جلسة فورية الآن محتوى صوتيًا إجماليًا يزيد
على حصتها البالغة 14400 ثانية (4 ساعات). وقد أُنهيت الجلسة؛ فابدأ جلسة
جديدة.
و`data.observed` بالثواني الكاملة، مقرَّبًا إلى الأعلى. وحيث توقفت الخدمة عن فك
الترميز عند السقف فإنها لم تعرف الطول الإجمالي الحقيقي، ولذلك تكون القيمة
المرصودة حدًا أدنى لا قياسًا دقيقًا.
وهي غير قابلة لإعادة المحاولة: فإعادة إرسال الصوت نفسه لا يمكن أن تنجح. قصّر
الوحدة، أو انتقل إلى واجهة النسخ الدفعي.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
fast_decoded_audio_too_long:
value:
error: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
code: AUDIO_DURATION_EXCEEDED
detail: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1800
observed: 3601
unit: seconds
bound: fast_audio_duration
session_audio_allowance_spent:
value:
error: session maximum audio duration exceeded; start a new session
code: AUDIO_DURATION_EXCEEDED
detail: session maximum audio duration exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 14400
observed: 14401
unit: seconds
bound: session_audio_duration
```
### الاستجابة `429`
تحديد المعدل في البوابة. تعتمد تفاصيل الاستجابة وترويسات إعادة المحاولة على النشر.
لا توجد قيمة موثقة.
### الاستجابة `500`
فشل نسخ Fast قبل إصدار سجل نهائي
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
transcription_failed:
value:
error: STT transcription failed
code: ASR_TRANSCRIPTION_FAILED
detail: STT transcription failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
استخدم Fast فقط بعد اكتمال وحدة صوت حوارية محدودة واحدة. حلّل كل سجل NDJSON، ولا تثبّت الناتج إلا من سجل نهائي، وأبقِ التسجيلات الطويلة مثل البودكاست والاجتماعات على Batch.
### [نفّذ تدفق HTTP](/ar/api-guides/realtime-http)
تعامل مع إدخال multipart وسجلات NDJSON والنهائية والمواعيد والتنظيف.
### [قارن وسيلة SDK](/ar/api-guides/socketio)
استخدم Socket.IO عندما تناسب SDK المنشورة لـJavaScript أو Python بيئة تشغيلك.
### [تعامل مع إخفاقات التدفق](/ar/api-guides/errors-and-rate-limits)
تعرّف على أخطاء التدفق المنظمة وإخفاقات HTTP على مستوى البوابة.
---
# واجهة Realtime HTTP
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/realtime-http
استخدم نقاط النهاية هذه عندما يلائم HTTP المتدفق بيئة التشغيل أكثر من Socket.IO. اختر نقطة النهاية من حالة الإدخال، وليس من زمن الاستجابة المطلوب فقط.
> **لـHTTP المباشرة فقط**
>
> تستخدم حزم SDK لـJavaScript وPython في الإصدار `0.18.0` بروتوكول Socket.IO والمسار `/socket.io` افتراضيًا؛ ولا تستدعي هذه المسارات. استخدم هذا القسم عند تنفيذ عميل HTTP مباشرة.
## اختر نقطة نهاية
| نقطة النهاية | عقد الإدخال | اخترها من أجل |
| --- | --- | --- |
| Fast · `/http/stt` | وحدة صوت واحدة مكتملة ومحدودة | دور وكيل مكتمل أو أمر صوتي أو عبارة حوارية قصيرة |
| Realtime ASR · `/http/stt-stream` | مقطع مؤطر واحد من صوت ما زال يصل | نسخ حي مع تحديثات ASR جزئية ونهائية |
| Realtime diarization · `/http/diarization-stream` | مقطع مؤطر واحد من صوت ما زال يصل | مقاطع متحدثين متزايدة لتدفق حي |
| TTS · `/http/tts` | طلب JSON واحد وتسجيل ثنائي بلا فواصل | فحص البروتوكول المباشر؛ واستخدام TTS عبر SDK للصوت القابل للتشغيل |
> **Fast ليس مسار التسجيلات الطويلة**
>
> حُسّن Fast لوحدة مكتملة لكنها محدودة وحساسة للزمن، مثل دور واحد في محادثة وكيلية. استخدم Batch للملفات الكبيرة والبودكاست والاجتماعات الطويلة ومعالجة الأرشيف.
## الاتصال والمصادقة
ابنِ الطلبات من `API_URL` المخصص مضافًا إليه المسار الأساسي `/realtime`. أرسل `x-api-key` من خادم موثوق. يحتاج المفتاح أيضًا إلى القدرة المخصصة: ASR الفوري لـFast وASR الحي، أو diarization للتمييز الحي، أو TTS للتوليف. تختلف أجسام الطلب: multipart لـFast، وثنائي مؤطر لـASR الحي وتمييز المتحدثين، وJSON لـTTS.
```bash
export API_URL="https://api.voice.humain.com"
export API_KEY="YOUR_API_KEY"
```
## العمليات
### [POST · النسخ السريع](/ar/api-reference/realtime-http/fast-transcription)
ارفع وحدة صوت مكتملة ومحدودة واستهلك أحداث النسخ المتدفقة.
### [POST · Realtime ASR](/ar/api-reference/realtime-http/realtime-asr)
أرسل مقطع صوت حي مؤطرًا واحدًا واستهلك ناتج ASR الجزئي أو النهائي.
### [POST · تمييز المتحدثين الفوري](/ar/api-reference/realtime-http/realtime-diarization)
أرسل مقطع صوت حي مؤطرًا واحدًا واستهلك مقاطع المتحدثين المتزايدة.
### [POST · تحويل النص إلى كلام](/ar/api-reference/realtime-http/text-to-speech)
التقط بروتوكول الخدمة بلا فواصل بتردد 16 kHz؛ واستخدم TTS عبر SDK عندما تحتاج صوتًا قابلاً للتشغيل.
## ملاحظات الإنتاج
- لطلبات الثنائي الحية، استخدم UUID واحدًا للتدفق عبر المقاطع واضبط علمي البداية والنهاية عند حدود دورة الحياة فقط.
- يجب أن يكون إدخال `PCM16` أحادي القناة بتردد 16 kHz وترتيب little-endian، وأن يحتوي على عدد زوجي من بايتات الصوت بعد ترويسة التحكم.
- أرسل طلب POST واحدًا لكل مقطع حي مؤطر. قد تحتوي استجابة `200` على صفر أو أكثر من سجلات NDJSON. لا تثبت الاكتمال إلا بعد سجل يحمل `is_final: true`؛ فلا يثبته علم النهاية في الطلب ولا انتهاء استجابة HTTP.
- في تمييز المتحدثين، لا تُبقِ أكثر من طلب POST واحد قيد التنفيذ لكل UUID، وأغلق كل استجابة قبل إرسال الإطار التالي. قد يفقد التداخل للـUUID نفسه ملكية الاستجابة.
- تعامل مع النصوص الجزئية كحالة عرض قابلة للاستبدال، ومع النصوص النهائية كناتج مثبت. لا تستنتج الترتيب من قيمة `seq` المعتمة.
- تحتوي إطارات خدمة TTS عبر HTTP على UUID وعلم نهاية وحمولة `PCM16`، لكن بلا طول للحمولة أو فاصل. لا تستطيع حدود قراءة HTTP العامة استعادة الإطارات بثقة؛ فضّل TTS عبر Socket.IO في SDK ووصفة TTS إلى WAV ما لم تملك بيئة التشغيل آلية تأطير صريحة.
## الخطوات التالية
### [دليل Realtime HTTP](/ar/api-guides/realtime-http)
نفّذ التأطير ومعالجة الأحداث والتنظيف.
### [دليل Socket.IO](/ar/api-guides/socketio)
قارن وسيلة SDK المنشورة ودورة حياتها.
---
# بث ASR مباشر من صوت ما زال يصل
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/realtime-http/realtime-asr
## العملية
**POST `/http/stt-stream`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/realtime`
- **عنوان URL للطلب:** `https://api.voice.humain.com/realtime/http/stt-stream`
## الوصف
هذه هي عملية HTTP المباشرة القياسية لـASR المباشر. يمثل
`POST /http/realtime-asr` اسمًا مستعارًا للتوافق؛ وينبغي للعملاء الجدد
استخدام هذا المسار. تستخدم حزم SDK لـJavaScript وPython في الإصدار `0.18.0`
بروتوكول Socket.IO ولا تستدعي أيًا من مساري HTTP.
أرسل طلب POST واحدًا لكل مقطع صوت عند وصوله. ابدأ كل جسم بترويسة التحكم نفسها
المكونة من 18 بايتًا: البايتات 0..15 هي UUID جديد غير صفري بصيغته الثنائية
الخام؛ ويحتوي البايت 16 على `is_start` في bit 0 و`is_final` في bit 1؛
والبايت 17 هو اللغة (`0=ar` و`1=en` و`2=codeswitch` و`255=auto`). أبقِ
بتات الأعلام المحجوزة صفرًا. ألحق صوت PCM16 خامًا أحادي القناة وغير فارغ
بترتيب little-endian وتردد 16 kHz، من دون ترويسة WAV. اضبط `is_start` في
المقطع الأول فقط، ولا تضبط أي علم في المقاطع الوسيطة، واضبط `is_final` في
آخر مقطع يحوي صوتًا؛ واضبط العلمين معًا لتدفق من مقطع واحد.
تحتوي استجابة `200` صفرًا أو أكثر من سجلات JSON المفصولة بأسطر جديدة. خزّن
عبر قراءات الشبكة وحلّل الأسطر المكتملة. عامل `is_speech_final` بوصفه حدًا
للكلام. لا تكمل التدفق إلا بعد ملاحظة `is_final: true`؛ فبت النهاية في
الطلب وانتهاء استجابة HTTP، بما في ذلك `200` فارغة، ليسا إشارتَي اكتمال.
عامل `seq` بوصفه مبهمًا وعالج السجلات وفق ترتيب وصولها الملحوظ. وإذا بدأ
الخرج، ينهي أي فشل لاحق بثَّ `200` الجزئي من دون إلحاق خطأ JSON.
استخدم `X-Api-Key` بقدرة ASR الفوري من خلفية موثوقة. ضع حدًا زمنيًا لكل
POST وقراءة وللتدفق كاملًا. لا يُعرّف إعادة تشغيل المقاطع ولا استئناف الجلسة؛
بعد فشل ملتبس، أوقف التدفق القديم وتخلص من الحالة المؤقتة وأعد البدء باستخدام
UUID جديد. لا يحدد العقد العام ما إذا كان ينبغي تداخل طلبات POST للمقاطع أو
تسلسلها؛ فاستخدم نمط التنسيق المخصص لبيئتك. ويحافظ انتهاء نافذة الاستجابة
غير النهائية العادية بعد ثانيتين على الجلسة. ويلغي إجهاض طلب POST أو انقضاء
مهلة الاستجابة النهائية الجلسةَ. كما تنتهي صلاحية الجلسة بعد 60 ثانية من دون
صوت عميل مقبول أو استجابة من محرك الاستدلال.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `X-Api-Key`
## المعاملات
لا توجد قيمة موثقة.
## جسم الطلب
- **مطلوب:** نعم
#### نوع المحتوى: `application/octet-stream`
**المخطط:**
لا توجد قيمة موثقة.
**الأمثلة:**
لا توجد قيمة موثقة.
## الاستجابات
### الاستجابة `200`
صفر أو أكثر من سجلات ASR المباشر بصيغة NDJSON. بعد بدء الخرج، ينهي أي فشل
لاحق البثَّ الجزئي من دون إلحاق خطأ JSON. ويتطلب الاكتمال ملاحظة سجل يحتوي
`is_final: true`.
#### نوع المحتوى: `application/x-ndjson`
**المخطط:**
```yaml
type: object
required:
- id
- seq
- transcription
- words
- is_final
- is_speech_final
properties:
id:
type: string
format: uuid
description: معرّف طلب النسخ.
seq:
type: integer
format: int64
description: قيمة تشخيصية مبهمة لا تضمن ترتيبًا ولا تفردًا.
transcription:
type: string
description: مقطع النص المنسوخ.
words:
type: array
items:
type: object
required:
- start_time
- end_time
- word
properties:
start_time:
type: number
format: float
end_time:
type: number
format: float
word:
type: string
description: نص الكلمة.
is_final:
type: boolean
description: تكون `true` فقط في سجل يكمل تدفق ASR المباشر.
is_speech_final:
type: boolean
description: تكون `true` عند حد مكتشف لمقطع كلام؛ ولا يكمل ذلك التدفق.
```
**الأمثلة:**
```yaml
partial:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello wor
words:
- start_time: 0
end_time: 0.45
word: hello
is_speech_final: false
is_final: false
final:
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
seq: 0
transcription: hello world
words:
- start_time: 0
end_time: 0.45
word: hello
- start_time: 0.46
end_time: 0.9
word: world
is_speech_final: true
is_final: true
```
### الاستجابة `400`
ترويسة تحكم أو UUID أو بايت لغة أو حمولة PCM غير صالحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
invalid_header:
summary: الترويسة قصيرة أو UUID صفري
value:
error: invalid audio upload
code: VALIDATION_FILE_CORRUPT
detail: invalid audio upload
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_language:
summary: بايت لغة غير صالح
value:
error: invalid language
code: VALIDATION_INVALID_LANGUAGE
detail: invalid language
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_audio:
summary: حمولة PCM فارغة
value:
error: audio upload is empty
code: VALIDATION_FILE_CORRUPT
detail: audio upload is empty
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
odd_audio:
summary: عدد بايتات حمولة PCM فردي
value:
error: audio must contain int16 samples
code: VALIDATION_INVALID_FORMAT
detail: audio must contain int16 samples
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى قدرة الصوت المطلوبة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `405`
الطريقة غير مسموحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `408`
لم يصل أي صوت على شبه الجلسة هذه داخل نافذة سكونها، فأُنهيت الجلسة
(RFC 9110 15.5.9). وهي غير قابلة لإعادة المحاولة بمعرّف الجلسة نفسه، الذي صار
مسجَّلًا كمنتهٍ ولا يُعاد استخدامه: ابدأ جلسة جديدة بمعرّف جديد ومع `is_start`.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
session_went_idle:
value:
error: session idle timeout exceeded; start a new session
code: SESSION_IDLE_TIMEOUT
detail: session idle timeout exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 900
observed: 901
unit: seconds
bound: session_idle
```
### الاستجابة `409`
يتعارض المقطع مع حالة شبه الجلسة التابع لها (RFC 9110 15.5.10):
فالمعرّف لم يُبدأ قط، أو أُنهي فعلًا، أو وصل `is_start` لمعرّف حيّ بالفعل.
وإجابة واحدة تغطي كل هذه الحالات، لذلك لا يمكن للتوقيت أن يغيّر العقد. ابدأ
جلسة جديدة بمعرّف جديد.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
not_live:
value:
error: session is not live; start a new session with is_start and a new id
code: SESSION_EXPIRED
detail: session is not live; start a new session with is_start and a new id
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `413`
تجاوز جسم الطلب حد البايتات المضبوط لهذا المسار الصوتي: 64 MiB لرفع
Fast، و16 MiB لإطارات ASR الفوري، و16 MiB لإطارات تمييز المتحدثين الفوري. وهو
غير قابل لإعادة المحاولة بالحجم نفسه؛ أعد إرسال وحدة أو مقطع أصغر.
ويسمّي `data.bound` حد البايتات الذي تم بلوغه — `fast_audio_bytes` أو
`realtime_asr_frame_bytes` أو `realtime_diarization_frame_bytes`. و
`data.observed` هو حجم الطلب الدقيق عندما يعلن العميل `Content-Length`، وهو
فيما عدا ذلك حد أدنى (الحد زائد بايت واحد)، لأن الجسم الذي لا يعلن طوله يُقطع
في أثناء القراءة ولا يُعرف حجمه الحقيقي أبدًا.
ولا تُبلَغ هذه الحالة إلا من عدّ بايتات. أما الطلب المقبولة بايتاته والذي يطول
صوته بعد فك الترميز فهو الحالة `422` برمز `AUDIO_DURATION_EXCEEDED` بدلًا
منها.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
declared_length_over_the_cap:
summary: أُعلن `Content-Length`، فالقيمة المرصودة دقيقة
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 20971520
unit: bytes
bound: realtime_asr_frame_bytes
streamed_body_over_the_cap:
summary: لا طول معلن، فالقيمة المرصودة هي الحد زائد بايت واحد
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 67108864
observed: 67108865
unit: bytes
bound: fast_audio_bytes
```
### الاستجابة `422`
حُلِّل الطلب بصورة صحيحة وكانت بايتاته مقبولة، لكن مقدار الصوت الذي
يطلب من الخدمة معالجته يتجاوز سقف هذه النقطة (RFC 9110 15.5.21). ورفع مضغوط
صغير يُفك إلى ساعات كثيرة هو هذه الحالة بالضبط، ولهذا لا تكون الحالة `413`.
ويسمّي `data.bound` السقف الصوتي الذي تم بلوغه:
* `fast_audio_duration` — إرسال Fast واحد فُك إلى أكثر من 1800 ثانية. قسّم
التسجيل أو استخدم واجهة النسخ الدفعي.
* `session_audio_duration` — أرسلت جلسة فورية الآن محتوى صوتيًا إجماليًا يزيد
على حصتها البالغة 14400 ثانية (4 ساعات). وقد أُنهيت الجلسة؛ فابدأ جلسة
جديدة.
و`data.observed` بالثواني الكاملة، مقرَّبًا إلى الأعلى. وحيث توقفت الخدمة عن فك
الترميز عند السقف فإنها لم تعرف الطول الإجمالي الحقيقي، ولذلك تكون القيمة
المرصودة حدًا أدنى لا قياسًا دقيقًا.
وهي غير قابلة لإعادة المحاولة: فإعادة إرسال الصوت نفسه لا يمكن أن تنجح. قصّر
الوحدة، أو انتقل إلى واجهة النسخ الدفعي.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
fast_decoded_audio_too_long:
value:
error: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
code: AUDIO_DURATION_EXCEEDED
detail: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1800
observed: 3601
unit: seconds
bound: fast_audio_duration
session_audio_allowance_spent:
value:
error: session maximum audio duration exceeded; start a new session
code: AUDIO_DURATION_EXCEEDED
detail: session maximum audio duration exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 14400
observed: 14401
unit: seconds
bound: session_audio_duration
```
### الاستجابة `429`
تم تحديد معدل طلب فوري. وتشترك ثلاثة مصادر مختلفة في هذه الحالة على
هذه المسارات، ويميز بينها حقل `code`:
* `SESSION_BYTE_RATE_EXCEEDED` — الصوت يصل أسرع مما يسمح به المعدل المستدام
للجلسة (أربعة أضعاف الزمن الحقيقي، مع اندفاع 16 MiB). التزم بـ`Retry-After`؛
فتنجح الحمولة نفسها بعدها. وتبقى الجلسة حيّة. و`data.bound` هو
`session_audio_rate_burst`.
* `CONCURRENCY_LIMIT_EXCEEDED` — لدى الحساب القابل للفوترة فعلًا من العمليات
المتزامنة من هذا النوع قيد التنفيذ ما تسمح به خطته. و`data.bound` هو
`account_concurrency_`.
* `SESSION_SLOTS_EXHAUSTED` — يحتفظ الحساب من أشباه جلسات HTTP المتزامنة بقدر
ما تسمح به هذه العملية.
كما يجيب حد معدل الطلبات لكل مفتاح في البوابة بالحالة `429` أيضًا ويبلّغ
`RATE_LIMIT_EXCEEDED`، وشكل جسمه يعتمد على النشر. وكل هذه قابلة لإعادة
المحاولة، ولا يستهلك أي منها رصيدًا ولا حصة.
**الترويسات:**
```yaml
Retry-After:
description: عدد الثواني التي يجب انتظارها قبل إعادة المحاولة.
schema:
type: integer
examples:
- 2
```
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
audio_arriving_too_fast:
value:
error: audio is arriving faster than this session allows; slow down to real time and retry
code: SESSION_BYTE_RATE_EXCEEDED
detail: audio is arriving faster than this session allows; slow down to real time and retry
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 33554432
unit: bytes
bound: session_audio_rate_burst
account_concurrency_exhausted:
value:
error: too many concurrent operations for this account
code: CONCURRENCY_LIMIT_EXCEEDED
detail: too many concurrent operations for this account
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 8
observed: 8
unit: operations
bound: account_concurrency_realtime_asr
```
### الاستجابة `500`
فشل ASR المباشر قبل إصدار سجل نهائي
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
transcription_failed:
value:
error: realtime ASR transcription failed
code: ASR_TRANSCRIPTION_FAILED
detail: realtime ASR transcription failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
ابنِ دورة الحياة الحية تاليًا: أعد استخدام UUID واحدًا عبر المقاطع المؤطرة، واستبدل حالة العرض الجزئية، وثبّت النتائج النهائية فقط، وأنهِ كل انتظار بموعد نهائي للتطبيق.
### [أطّر صوت HTTP الحي](/ar/api-guides/realtime-http)
أنشئ إطارات الطلب وطابق صفرًا أو أكثر من سجلات NDJSON في كل استجابة.
### [استخدم SDK لـSocket.IO](/ar/api-guides/socketio)
اتبع دورة حياة SDK المنشورة عندما لا تحتاج إلى HTTP المباشرة.
---
# بناء خط زمني للمتحدثين من صوت ما زال يصل
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/realtime-http/realtime-diarization
## العملية
**POST `/http/diarization-stream`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/realtime`
- **عنوان URL للطلب:** `https://api.voice.humain.com/realtime/http/diarization-stream`
## الوصف
استخدم هذه العملية لبناء خط زمني للمتحدثين بينما لا يزال صوت PCM يصل.
وهي لا تنسخ الكلام ولا تتعرف على أشخاص حقيقيين. تستخدم حزم SDK لـJavaScript
وPython في الإصدار `0.18.0` بروتوكول Socket.IO؛ ولا ترسل طلب HTTP هذا.
أرسل من خلفية موثوقة إطارًا ثنائيًا مكتملًا واحدًا في كل POST مع
`X-Api-Key` وقدرة تمييز المتحدثين. أعد استخدام UUID جديد غير صفري واحد حتى
ينتهي التدفق، ولا تُبقِ أكثر من POST واحد قيد التنفيذ لهذا UUID. قد تستبدل
الطلبات المتزامنة للـUUID نفسه ملكية الاستجابة. التقط الصوت في قائمة انتظار
محدودة، ودع مرسلاً واحدًا يفرغها ويغلق كل استجابة قبل إرسال الإطار التالي.
يمكن تشغيل تدفقات UUID مختلفة بالتوازي.
لكل إطار ترويسة من 18 بايتًا يتبعها صوت PCM16 خام أحادي القناة غير فارغ
بترتيب little-endian وتردد 16 kHz. البايتات 0..15 هي UUID. في البايت 16،
يمثل bit 0 الحقل `is_start` ويمثل bit 1 الحقل `is_final`؛ ويجب أن تكون البتات
المحجوزة 2..7 أصفارًا، ويُرفض أي إطار يضبط أيًا منها بالحالة `400`
`VALIDATION_INVALID_FORMAT`. يجب أن يكون البايت 17 أحد `0` (العربية) أو `1`
(الإنجليزية) أو `2` (تبديل اللغات) أو `255` (تلقائي)، لكنه يُهمل بعد
التحقق ولا يغير تمييز المتحدثين. اضبط علم البدء في الإطار الأول فقط، وعلم
النهاية في آخر إطار صوت فعلي، والعلمين معًا (`0x03`) لتدفق من إطار واحد.
يجب أن يتضمن كل طلب حمولة PCM غير فارغة ذات طول زوجي؛ ولا يوجد فاصل نهاية فارغ.
قد تحتوي كل استجابة `200` صفرًا أو أكثر من سجلات NDJSON. خزّن قراءات الشبكة
ولا تقسّم إلا عند السطر الجديد. اجمع السجلات من كل استجابة للـUUID. راكم
فروق `final_segments` التي لم تُر من قبل، واستبدل لقطة `active_segments`
السابقة، ورتب الخط الزمني الموحّد بحسب `start_time`. تسميات المتحدثين نسبية
إلى تدفق واحد وليست هويات. أزمنة المقاطع بالثواني منذ بدء التدفق. أبقِ الذيل
النشط غير الفارغ في السجل النهائي مؤقتًا، ولا تعِد تسميته نهائيًا.
لا يكمل التدفق إلا سجل ملحوظ يحتوي `is_final: true`. لا يكمله بت النهاية
في الطلب ولا `200` فارغة ولا EOF للاستجابة ولا المهلة. وإذا بدأ الخرج، ينهي
أي فشل لاحق بثَّ `200` الجزئي من دون إلحاق خطأ JSON. ويحافظ انتهاء نافذة
الاستجابة غير النهائية العادية بعد ثانيتين على الجلسة. ويلغي إجهاض طلب POST
أو انقضاء مهلة الاستجابة النهائية الجلسةَ، كما تنتهي صلاحية الجلسة بعد 60
ثانية من دون نشاط من العميل أو من محرك الاستدلال. لا يوجد عقد عبر HTTP لإعادة تشغيل
المقاطع أو الاستئناف أو idempotency. بعد فشل ملتبس، أوقف المنتج وأغلق كل
استجابة واحتفظ بالخط الزمني بوصفه غير مكتمل، ثم تعافَ باستخدام UUID جديد بدل
إعادة تشغيل مقطع قديم.
تختار الخدمة نموذج تمييز المتحدثين الفوري؛ ولا يملك العملاء محدد نموذج. يعيد
غياب ضبط النموذج `400 DIARIZATION_MODEL_NOT_FOUND`. وتندمج أخطاء سعة الخلفية
والاستدلال حاليًا في `500 DIARIZATION_FAILED` قابل لإعادة المحاولة؛ وقد تعيد
بوابة الإنتاج بصورة مستقلة `429` بتفاصيل تعتمد على النشر.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `X-Api-Key`
## المعاملات
لا توجد قيمة موثقة.
## جسم الطلب
- **مطلوب:** نعم
#### نوع المحتوى: `application/octet-stream`
**المخطط:**
لا توجد قيمة موثقة.
**الأمثلة:**
لا توجد قيمة موثقة.
## الاستجابات
### الاستجابة `200`
صفر أو أكثر من سجلات تمييز المتحدثين بصيغة NDJSON. بعد بدء الخرج، ينهي أي
فشل لاحق البثَّ الجزئي من دون إلحاق خطأ JSON. ويتطلب الاكتمال ملاحظة سجل
يحتوي `is_final: true`.
**الترويسات:**
```yaml
Cache-Control:
schema:
type: string
enum:
- no-store
description: يمنع الوسطاء من تخزين سجلات الخط الزمني للمتحدثين مؤقتًا.
```
#### نوع المحتوى: `application/x-ndjson`
**المخطط:**
```yaml
type: object
required:
- id
- final_segments
- active_segments
- is_final
properties:
id:
type: string
format: uuid
description: معرّف طلب تمييز المتحدثين.
final_segments:
type: array
description: |-
المقاطع التي أصبحت نهائية حديثًا في هذا السجل. راكم المقاطع التي لم تُر
عبر السجلات؛ فهذه ليست لقطة تراكمية للخط الزمني.
items:
type: object
required:
- start_time
- end_time
- speaker
properties:
start_time:
type: number
format: float
description: وقت بداية المقطع بالثواني نسبةً إلى بداية التدفق.
end_time:
type: number
format: float
description: وقت نهاية المقطع بالثواني نسبةً إلى بداية التدفق.
speaker:
type: string
description: تسمية نسبية إلى التدفق مثل `SPEAKER_01`، وليست هوية في العالم الحقيقي.
active_segments:
type: array
description: |-
لقطة بديلة للمقاطع المتغيرة. استبدل اللقطة النشطة السابقة بدل الإلحاق بها.
قد يحتفظ السجل النهائي بأفضل ذيل مؤقت معروف وغير فارغ.
items:
type: object
required:
- start_time
- end_time
- speaker
properties:
start_time:
type: number
format: float
description: وقت بداية المقطع بالثواني نسبةً إلى بداية التدفق.
end_time:
type: number
format: float
description: وقت نهاية المقطع بالثواني نسبةً إلى بداية التدفق.
speaker:
type: string
description: تسمية نسبية إلى التدفق مثل `SPEAKER_01`، وليست هوية في العالم الحقيقي.
is_final:
type: boolean
description: تكون `true` فقط في سجل يكمل تدفق تمييز المتحدثين.
```
**الأمثلة:**
```yaml
incremental:
summary: فرق المقاطع النهائية مع اللقطة النشطة الحالية
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
final_segments:
- start_time: 0
end_time: 1.5
speaker: SPEAKER_01
active_segments:
- start_time: 1.5
end_time: 3
speaker: SPEAKER_02
is_final: false
final:
summary: فرق نهائي لاحق مع أفضل ذيل مؤقت معروف
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
final_segments:
- start_time: 1.5
end_time: 3
speaker: SPEAKER_02
active_segments:
- start_time: 3
end_time: 3.4
speaker: SPEAKER_01
is_final: true
```
### الاستجابة `400`
إطار تمييز متحدثين أو بدء تدفق أو ضبط نموذج خدمة غير صالح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
invalid_header:
summary: الترويسة قصيرة أو UUID صفري
value:
error: invalid audio upload
code: VALIDATION_FILE_CORRUPT
detail: invalid audio upload
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_language:
summary: بايت اللغة ليس 0 أو 1 أو 2 أو 255
value:
error: invalid language
code: VALIDATION_INVALID_LANGUAGE
detail: invalid language
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_audio:
summary: حمولة PCM فارغة
value:
error: audio upload is empty
code: VALIDATION_FILE_CORRUPT
detail: audio upload is empty
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
odd_audio:
summary: عدد بايتات حمولة PCM فردي
value:
error: audio must contain int16 samples
code: VALIDATION_INVALID_FORMAT
detail: audio must contain int16 samples
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
missing_start:
summary: الإطار الأول لا يضبط بت البدء
value:
error: missing is_start flag
code: VALIDATION_REQUIRED_FIELD
detail: missing is_start flag
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
missing_model:
summary: تمييز المتحدثين الفوري غير مضبوط
value:
error: diarization model not found
code: DIARIZATION_MODEL_NOT_FOUND
detail: diarization model not found
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى قدرة الصوت المطلوبة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `405`
الطريقة غير مسموحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `408`
لم يصل أي صوت على شبه الجلسة هذه داخل نافذة سكونها، فأُنهيت الجلسة
(RFC 9110 15.5.9). وهي غير قابلة لإعادة المحاولة بمعرّف الجلسة نفسه، الذي صار
مسجَّلًا كمنتهٍ ولا يُعاد استخدامه: ابدأ جلسة جديدة بمعرّف جديد ومع `is_start`.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
session_went_idle:
value:
error: session idle timeout exceeded; start a new session
code: SESSION_IDLE_TIMEOUT
detail: session idle timeout exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 900
observed: 901
unit: seconds
bound: session_idle
```
### الاستجابة `409`
يتعارض المقطع مع حالة شبه الجلسة التابع لها (RFC 9110 15.5.10):
فالمعرّف لم يُبدأ قط، أو أُنهي فعلًا، أو وصل `is_start` لمعرّف حيّ بالفعل.
وإجابة واحدة تغطي كل هذه الحالات، لذلك لا يمكن للتوقيت أن يغيّر العقد. ابدأ
جلسة جديدة بمعرّف جديد.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
not_live:
value:
error: session is not live; start a new session with is_start and a new id
code: SESSION_EXPIRED
detail: session is not live; start a new session with is_start and a new id
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `413`
تجاوز جسم الطلب حد البايتات المضبوط لهذا المسار الصوتي: 64 MiB لرفع
Fast، و16 MiB لإطارات ASR الفوري، و16 MiB لإطارات تمييز المتحدثين الفوري. وهو
غير قابل لإعادة المحاولة بالحجم نفسه؛ أعد إرسال وحدة أو مقطع أصغر.
ويسمّي `data.bound` حد البايتات الذي تم بلوغه — `fast_audio_bytes` أو
`realtime_asr_frame_bytes` أو `realtime_diarization_frame_bytes`. و
`data.observed` هو حجم الطلب الدقيق عندما يعلن العميل `Content-Length`، وهو
فيما عدا ذلك حد أدنى (الحد زائد بايت واحد)، لأن الجسم الذي لا يعلن طوله يُقطع
في أثناء القراءة ولا يُعرف حجمه الحقيقي أبدًا.
ولا تُبلَغ هذه الحالة إلا من عدّ بايتات. أما الطلب المقبولة بايتاته والذي يطول
صوته بعد فك الترميز فهو الحالة `422` برمز `AUDIO_DURATION_EXCEEDED` بدلًا
منها.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
declared_length_over_the_cap:
summary: أُعلن `Content-Length`، فالقيمة المرصودة دقيقة
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 20971520
unit: bytes
bound: realtime_asr_frame_bytes
streamed_body_over_the_cap:
summary: لا طول معلن، فالقيمة المرصودة هي الحد زائد بايت واحد
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 67108864
observed: 67108865
unit: bytes
bound: fast_audio_bytes
```
### الاستجابة `422`
حُلِّل الطلب بصورة صحيحة وكانت بايتاته مقبولة، لكن مقدار الصوت الذي
يطلب من الخدمة معالجته يتجاوز سقف هذه النقطة (RFC 9110 15.5.21). ورفع مضغوط
صغير يُفك إلى ساعات كثيرة هو هذه الحالة بالضبط، ولهذا لا تكون الحالة `413`.
ويسمّي `data.bound` السقف الصوتي الذي تم بلوغه:
* `fast_audio_duration` — إرسال Fast واحد فُك إلى أكثر من 1800 ثانية. قسّم
التسجيل أو استخدم واجهة النسخ الدفعي.
* `session_audio_duration` — أرسلت جلسة فورية الآن محتوى صوتيًا إجماليًا يزيد
على حصتها البالغة 14400 ثانية (4 ساعات). وقد أُنهيت الجلسة؛ فابدأ جلسة
جديدة.
و`data.observed` بالثواني الكاملة، مقرَّبًا إلى الأعلى. وحيث توقفت الخدمة عن فك
الترميز عند السقف فإنها لم تعرف الطول الإجمالي الحقيقي، ولذلك تكون القيمة
المرصودة حدًا أدنى لا قياسًا دقيقًا.
وهي غير قابلة لإعادة المحاولة: فإعادة إرسال الصوت نفسه لا يمكن أن تنجح. قصّر
الوحدة، أو انتقل إلى واجهة النسخ الدفعي.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
fast_decoded_audio_too_long:
value:
error: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
code: AUDIO_DURATION_EXCEEDED
detail: decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1800
observed: 3601
unit: seconds
bound: fast_audio_duration
session_audio_allowance_spent:
value:
error: session maximum audio duration exceeded; start a new session
code: AUDIO_DURATION_EXCEEDED
detail: session maximum audio duration exceeded; start a new session
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 14400
observed: 14401
unit: seconds
bound: session_audio_duration
```
### الاستجابة `429`
تم تحديد معدل طلب فوري. وتشترك ثلاثة مصادر مختلفة في هذه الحالة على
هذه المسارات، ويميز بينها حقل `code`:
* `SESSION_BYTE_RATE_EXCEEDED` — الصوت يصل أسرع مما يسمح به المعدل المستدام
للجلسة (أربعة أضعاف الزمن الحقيقي، مع اندفاع 16 MiB). التزم بـ`Retry-After`؛
فتنجح الحمولة نفسها بعدها. وتبقى الجلسة حيّة. و`data.bound` هو
`session_audio_rate_burst`.
* `CONCURRENCY_LIMIT_EXCEEDED` — لدى الحساب القابل للفوترة فعلًا من العمليات
المتزامنة من هذا النوع قيد التنفيذ ما تسمح به خطته. و`data.bound` هو
`account_concurrency_`.
* `SESSION_SLOTS_EXHAUSTED` — يحتفظ الحساب من أشباه جلسات HTTP المتزامنة بقدر
ما تسمح به هذه العملية.
كما يجيب حد معدل الطلبات لكل مفتاح في البوابة بالحالة `429` أيضًا ويبلّغ
`RATE_LIMIT_EXCEEDED`، وشكل جسمه يعتمد على النشر. وكل هذه قابلة لإعادة
المحاولة، ولا يستهلك أي منها رصيدًا ولا حصة.
**الترويسات:**
```yaml
Retry-After:
description: عدد الثواني التي يجب انتظارها قبل إعادة المحاولة.
schema:
type: integer
examples:
- 2
```
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
audio_arriving_too_fast:
value:
error: audio is arriving faster than this session allows; slow down to real time and retry
code: SESSION_BYTE_RATE_EXCEEDED
detail: audio is arriving faster than this session allows; slow down to real time and retry
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 16777216
observed: 33554432
unit: bytes
bound: session_audio_rate_burst
account_concurrency_exhausted:
value:
error: too many concurrent operations for this account
code: CONCURRENCY_LIMIT_EXCEEDED
detail: too many concurrent operations for this account
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 8
observed: 8
unit: operations
bound: account_concurrency_realtime_asr
```
### الاستجابة `500`
فشل تمييز المتحدثين قبل إصدار سجل نهائي. تندمج حاليًا أخطاء سعة الخلفية
والاستدلال في هذه الاستجابة القابلة لإعادة المحاولة.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
diarization_failed:
value:
error: realtime diarization failed
code: DIARIZATION_FAILED
detail: realtime diarization failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
أكمل دورة حياة التدفق الحي قبل استهلاك تسميات المتحدثين: احتفظ بـUUID واحد عبر المقاطع المؤطرة، وأرسل طلبات UUID نفسه بالتتابع، ووفّق الإضافات النهائية مع أحدث لقطة نشطة، ونظّف عند نتيجة نهائية أو خطأ منظم أو موعد نهائي.
### [نفّذ تمييز المتحدثين عبر HTTP](/ar/api-guides/realtime-http)
طبّق عقد الإطار الثنائي ودورة حياة النتائج المتزايدة.
### [قارن وسيلة SDK](/ar/api-guides/socketio)
استخدم عميل Socket.IO المنشور عندما يلائم تطبيقك أكثر.
---
# التقاط تدفق إطارات خدمة TTS عبر HTTP
Locale: ar
Source: https://docs.voice.humain.com/ar/api-reference/realtime-http/text-to-speech
## العملية
**POST `/http/tts`**
- **عنوان URL الأساسي:** `https://api.voice.humain.com/realtime`
- **عنوان URL للطلب:** `https://api.voice.humain.com/realtime/http/tts`
## الوصف
هذه عملية مباشرة عبر HTTP للمنصة. تستخدم حزم SDK لـJavaScript وPython في
الإصدار `0.18.0` بروتوكول Socket.IO ولا تستدعي هذا المسار. أرسل الطلب من
خلفية موثوقة مع `X-Api-Key` وقدرة TTS.
أرسل UUID جديدًا في `id`، ونصًا في `text` على المستوى الأعلى يحتوي على حرف Unicode واحد أو رقم واحد على الأقل بعد إزالة الفراغات الطرفية، ومفتاح النموذج الصريح `nebula`.
لاختيار صوت متوقع، أرسل إما `voice_id` واحدًا بالضبط أو عنصرًا واحدًا في
`voice_references`، ولا تجمع بينهما. احصل على `voice_id` عبر `listVoices()`
أو `list_voices()` في SDK؛ فلا توجد عملية HTTP لسرد الأصوات. يعرّف UUID المعاد واحدة من هويات
الأصوات السبع متعددة اللغات. نسخها الفعلية داخلية، ويُرفض الاستخدام المباشر
لـUUID أي نسخة فعلية. إذا حُذف
`model`، يستخدم النشر مفتاح النموذج الافتراضي المضبوط لديه، مع الرجوع إلى
`nebula`. وإذا حُذف محدد الصوت، يعتمد اختيار الصوت على النشر.
تحسب الخدمة نقاط ترميز Unicode، لا بايتات UTF-8 ولا عناقيد الرسوم المعروضة.
وتُحفظ الفراغات في البداية والنهاية وتُحسب ضمن الحد. الحدود الافتراضية شاملةً
هي 500 نقطة ترميز للحسابات المجانية و1000 للحسابات القياسية وحسابات
المؤسسات. وتستخدم الفئات المفقودة أو غير المعروفة الحد المجاني. ويمكن لعمليات
النشر تجاوز هذه الحدود بصورة مستقلة عبر `TTS_MAX_INPUT_CHARACTERS_FREE`
و`TTS_MAX_INPUT_CHARACTERS_STANDARD` و`TTS_MAX_INPUT_CHARACTERS_ENTERPRISE`،
لذلك لا يعلن هذا المخطط قيمة `maxLength` ثابتة عمدًا.
يجب أن يكون `audio` المرجعي RIFF/WAVE بترميز base64 القياسي، وأن يحتوي
صوت PCM16 أحادي القناة غير فارغ، وأن يرافقه نصه.
جسم استجابة HTTP `200` تسلسل بلا فواصل من إطارات الخدمة: 16 بايتًا
خامًا لـUUID، ثم بايت علم النهاية، ثم بايتات PCM16 بترتيب little-endian وتردد
16 kHz. لا تحافظ حدود القراءة العادية عبر HTTP على حدود إطارات الخدمة؛ لذلك
لا يمكن فك هذا الجسم عمومًا بوصفه PCM خامًا أو WAV. احفظه فقط كتسجيل بروتوكول.
استخدم TTS عبر Socket.IO ووصفة TTS-to-WAV للحصول على خرج قابل للتشغيل.
طبّق مهلًا نهائية محدودة للاتصال وعدم النشاط أو القراءة والعملية كاملة. لا
يعني EOF أو الإلغاء من دون علم نهاية معروف الحدود اكتمالًا. ويلغي إجهاض طلب
HTTP التصنيع الجاري له وحده. وينهي الفشل بعد إرسال البايتات البثَّ الثنائي
الجزئي؛ ولا تلحق الخدمة أبدًا مستند JSON للخطأ بجسم `200` الثنائي. افصل
البايتات الجزئية عن الخرج المكتمل. لا تدعم هذه العملية عقد idempotency؛
استخدم UUID جديدًا لإعادة محاولة يوافق عليها التطبيق.
## المصادقة
- `ApiKeyAuth` — type: `apiKey`; الموضع: `header`; الترويسات: `X-Api-Key`
## المعاملات
لا توجد قيمة موثقة.
## جسم الطلب
- **مطلوب:** نعم
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
additionalProperties: false
required:
- id
- text
not:
required:
- voice_id
- voice_references
properties:
voice_id: {}
voice_references:
type: array
properties:
id:
type: string
format: uuid
description: UUID ارتباط جديد تكرره ترويسات إطارات الخدمة. وهو ليس مفتاح idempotency.
text:
type: string
minLength: 1
description: |-
النص المراد تصنيعه. يجب أن يحتوي حرفًا أو رقمًا واحدًا على الأقل من
Unicode بعد إزالة المسافات: فالنص المكوّن من مسافات فقط يُرفض بالرمز
`VALIDATION_REQUIRED_FIELD`، والنص الذي لا يحتوي حرفًا ولا رقمًا (مثل إدخال من
علامات ترقيم فقط كـ`-` أو `...` أو `؟`) يُرفض بالرمز
`VALIDATION_INVALID_PARAM`. وكلاهما HTTP 400 مع `retryable: false`، ولا تُحاول
عملية التصنيع.
ويُحسب الطول بنقاط ترميز Unicode، لا ببايتات UTF-8 ولا بعناقيد المحارف
المعروضة؛ وتُحفظ المسافات في البداية والنهاية وتُحسب. والافتراضيات الشاملة هي
500 نقطة ترميز للحسابات المجانية و1,000 للحسابات القياسية والمؤسسية. وتستخدم
الفئات المفقودة أو غير المعروفة 500. ويمكن للنشر تغيير حد كل فئة على حدة، ولذلك لا
تُذكر قيمة `maxLength` ثابتة.
وتجاوز حد الفئة هو HTTP **422** بالرمز `CHARACTER_COUNT_EXCEEDED` ومع
`retryable: false` وكائن `data` يكون `bound` فيه `tts_input_characters`
و`unit` فيه `characters` و`limit` هو السقف المضبوط و`observed` هو عدد نقاط
الترميز. والعدد وحدة عمل دلالية لا حجم تمثيل، ولهذا هو 422 لا 413.
وهذا الحقل نص UTF-8 عادي، وليس SSML. ولا يُحلَّل الترميز ولا يُتحقق منه: فأقواس
الزوايا لا تحمل أي معنى، وتُحسب في حد الأحرف كأي محارف أخرى، وقد يُنطَق اسم
الوسم. لا ترسل SSML ولا تعتمد على أي دلالات ترميز.
model:
type: string
minLength: 1
description: |-
مفتاح النموذج المخصص. إذا حُذف، يستخدم النشر مفتاح النموذج الافتراضي
المضبوط لديه مع الرجوع إلى `nebula`. استخدم `nebula` في الأمثلة القابلة للنقل.
voice_id:
type: string
format: uuid
description: |-
UUID هوية الصوت الذي يُحصل عليه عبر Socket.IO أو قائمة أصوات SDK. ولا
توجد عملية HTTP لسرد الأصوات. تُختار النسخة العربية عندما يحتوي `text` على
أي حرف Unicode من نظام الكتابة العربي؛ وإلا تُختار النسخة الإنجليزية. معرفات
UUID للنسخ الفعلية داخلية ومرفوضة. لا تجمع بينه وبين `voice_references`: فإرسالهما معًا
يُرفض بالحالة HTTP 400 وبالرمز `VALIDATION_INVALID_PARAM` ومع
`retryable: false`، ولا تُحاول عملية التصنيع. وتُحسب مصفوفة `voice_references`
الفارغة الصريحة إرسالًا له، أما `null` فلا — إذ إن `voice_id` مع
`voice_references: null` صالح ويستخدم `voice_id`.
voice_references:
type:
- array
- "null"
minItems: 1
maxItems: 1
description: |-
مقطع مرجعي واحد بالضبط لتكييف الصوت. لا تجمع بينه وبين `voice_id`.
وحد `maxItems: 1` مفروض في وقت التشغيل: فإرسال أكثر من ذلك يُرفض بالحالة
HTTP **422** وبالرمز `VOICE_REFERENCE_COUNT_EXCEEDED` ومع `retryable: false`
وكائن `data` يكون `bound` فيه `tts_voice_reference_count` و`unit` فيه
`references`. ويُفحص كل حد على هذه المصفوفة ومحتوياتها قبل أي بحث عن نموذج أو
قبول أو محاسبة.
وثلاث طرق للقول «لا مرجع» ليست متكافئة:
* حذف الخاصية، أو إرسال `null`، كلاهما يعني «لا مرجع». و`null` مقبول لتوافق
العملاء، لأن كثيرًا من العملاء وحزم SDK المولَّدة يسلسلون الحقل الاختياري غير
المضبوط بوصفه `null`، وهو معلن هنا `nullable: true` لا مجرد متساهَل معه.
ولذلك فإن `voice_id` مع `null` صالح ويستخدم `voice_id`: فالقيمة الفارغة ليست
محدد صوت ثانيًا.
* أما المصفوفة الفارغة الصريحة `[]` فتُرفض بالحالة HTTP 400 وبالرمز
`VALIDATION_INVALID_PARAM`. فهي مصفوفة صحيحة التكوين تخالف `minItems: 1`
المعلن، ولذلك هي خلاف لقيد لا قيمة غائبة، بخلاف `null`. احذف الخاصية أو أرسل
`null` بدلًا من ذلك.
items:
type: object
additionalProperties: false
required:
- audio
- text
properties:
audio:
type: string
minLength: 1
description: |-
RIFF/WAVE بترميز base64 القياسي يحتوي صوتًا مرجعيًا PCM16 أحادي
القناة غير فارغ. ويجب أن يكون base64 قانونيًا بصرامة: فتُرفض فواصل الأسطر
والمسافات والأبجدية الآمنة للعناوين وبتات الحشو غير الصفرية بالحالة HTTP 400
وبالرمز `VALIDATION_INVALID_FORMAT`، وكذلك كل ما ليس ملف RIFF/WAVE بصيغة
PCM16 أحادي القناة.
وينطبق سقفان، كلاهما مشتق من النموذج المنشور وكلاهما مفحوص قبل أي بحث عن نموذج
أو قبول أو محاسبة. ويُقيَّم سقف الحجم حسابيًا من طول base64 قبل فك ترميز
الحمولة، لذلك لا يُنشأ المرجع المفرط في الحجم أبدًا؛ أما سقف المدة فيأتي
بالضرورة بعد فك الترميز وتحليل WAV. يجب ألا يتجاوز الحجم بعد فك الترميز سقف
البايتات في النشر، وافتراضيه **2 MiB** — وتجاوزه هو HTTP **413** والرمز
`PAYLOAD_TOO_LARGE`، مع `data.bound` بقيمة `tts_voice_reference_bytes`
و`unit` بقيمة `bytes`، لأن الرفض يُبلَغ من عدّ بايتات. ويجب ألا تتجاوز المدة
بعد فك الترميز سقف المدة في النشر، وافتراضيه **15 ثانية** — وتجاوزه هو
HTTP **422** والرمز `AUDIO_DURATION_EXCEEDED`، مع `data.bound` بقيمة
`tts_voice_reference_duration` و`unit` بقيمة `seconds`. وسقف المدة مطابق لحد
المرجع في النموذج المنشور نفسه، والصوت الزائد فوقه لم يُستخدم قط. وتُحسب المدة
من معدل العينات الذي يعلنه الملف نفسه، لذلك يُقاس المقطع بأي معدل عينات
بالثواني الحقيقية. والحدان شاملان: يُقبل المقطع الذي يقع عند السقف بالضبط.
contentEncoding: base64
text:
type: string
minLength: 1
maxLength: 500
description: |-
نص غير فارغ مقابل للصوت المرجعي، محسوبًا بنقاط ترميز Unicode. ويجب أن
يحتوي حرفًا أو رقمًا واحدًا على الأقل من Unicode: فالنص المفقود أو المكوّن من
مسافات فقط يُرفض بالحالة HTTP 400 وبالرمز `VALIDATION_REQUIRED_FIELD`، والنص
الذي لا يحتوي حرفًا ولا رقمًا يُرفض بالحالة HTTP 400 وبالرمز
`VALIDATION_INVALID_PARAM`. وتجاوز السقف هو HTTP **422** والرمز
`CHARACTER_COUNT_EXCEEDED`، مع `data.bound` بقيمة
`tts_voice_reference_text_characters`. وهذا السقف مستقل عن حد `text` لكل فئة
ولا يستهلكه: فهو يصف مقطعًا مرجعيًا واحدًا ثابت المدة لا عبء التصنيع. ويمكن
للنشر أن يخفضه لكن لا أن يرفعه أبدًا.
```
**الأمثلة:**
```yaml
basic:
summary: صوت يختاره النشر
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
text: Hello from HUMAIN Voice
model: nebula
with_voice:
summary: صوت صريح مختار من قائمة أصوات SDK
value:
id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
text: Welcome to HUMAIN Voice
model: nebula
voice_id: af52a907-1086-46f7-8f5d-72317875d7bd
```
## الاستجابات
### الاستجابة `200`
تسلسل بلا فواصل من إطارات خدمة TTS، وليس PCM خامًا ولا WAV. ليست
مقاطع القراءة العادية عبر HTTP حدودًا لإطارات الخدمة. وحده عميل يملك آلية
تأطير خاصة بالبيئة يستطيع تحديد علم النهاية؛ ولا يثبت EOF وحده الاكتمال.
#### نوع المحتوى: `application/octet-stream`
**المخطط:**
لا توجد قيمة موثقة.
**الأمثلة:**
لا توجد قيمة موثقة.
### الاستجابة `400`
إدخال مشوّه، بما في ذلك `id` طلب غير قابل للتحليل، أو نص أو مرجع صوتي
مفقود أو غير قابل للاستخدام. وهذه حالات فشل تحقق غير قابلة لإعادة المحاولة وتحدث
قبل أن يبدأ التصنيع.
ويُبلَّغ أيضًا عن النص الصالح الذي ترفضه سياسة محتوى TTS بالرمز
`TTS_INPUT_NOT_ALLOWED`. وهو غير قابل لإعادة المحاولة: فلن يُقبل النص نفسه،
ولذلك غيّر النص قبل إرسال طلب آخر.
ويُبلَّغ عن `id` الطلب المشوّه بالرمز `VALIDATION_INVALID_FORMAT`، مع كل حالات
فشل الجسم المشوّه الأخرى: فـ`id` يُحلَّل أثناء فك ترميز JSON، ولذلك تُفشل القيمة
غير القابلة للتحليل الجسم كله بدلًا من أن تصل إلى فحص مخصص. و`id` الطلب نفسه لا
ينتج عنه أبدًا `VALIDATION_INVALID_UUID` على هذا المسار.
أما `voice_id` المُرسَل من العميل فيُبلَّغ عنه هنا (SAU-2258): فـ`voice_id` الذي
ليس UUID صالحًا هو `VALIDATION_INVALID_UUID`، و`voice_id` صالح البنية لكنه لا
يحدد صوتًا متاحًا هو `TTS_VOICE_NOT_FOUND`. وكلاهما `400` وغير قابل لإعادة
المحاولة — فإعادة إرسال `voice_id` نفسه لا يمكن أن تنجح؛ صحّحه أو أرسل
`voice_references` بدلًا منه. (أما بيانات الصوت الموجودة لكن الناقصة أو التالفة،
أو انقطاع تخزين/قاعدة بيانات مثبت، فهي حالات من جهة الخادم يُبلَّغ عنها بالحالة
`500`/`503` — راجع استجابتَي `500` و`503`.)
وتجاوزات النص والمرجع ليست هنا: فتجاوز حد أحرف الفئة أو حد نص المرجع أو عدد
المراجع هو الحالة `422`، والمرجع الذي يزيد حجمه بعد فك الترميز هو الحالة `413`.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
invalid_body:
value:
error: Invalid request body
code: VALIDATION_INVALID_FORMAT
detail: Invalid request body
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_id:
summary: "`id` الطلب ليس UUID صالحًا، فيفشل فك ترميز الجسم"
value:
error: Invalid request body
code: VALIDATION_INVALID_FORMAT
detail: Invalid request body
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_text:
summary: النص فارغ أو يحتوي على فراغات Unicode فقط
value:
error: TTS input must contain non-whitespace text
code: VALIDATION_REQUIRED_FIELD
detail: TTS input must contain non-whitespace text
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
voice_selector_conflict:
summary: أُرسل voice_id وvoice_references معًا
value:
error: voice_id and voice_references are mutually exclusive
code: VALIDATION_INVALID_PARAM
detail: voice_id and voice_references are mutually exclusive
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
empty_voice_reference_array:
summary: مصفوفة فارغة صريحة؛ احذف الخاصية بدلًا من ذلك
value:
error: voice_references must contain exactly one reference when present; omit the field to use the default voice
code: VALIDATION_INVALID_PARAM
detail: voice_references must contain exactly one reference when present; omit the field to use the default voice
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
reference_audio_not_a_wav:
summary: الصوت المرجعي ليس RIFF/WAVE بترميز base64 قانوني وPCM16 أحادي القناة
value:
error: "voice_references[0].audio is not valid reference audio: audio must be a RIFF/WAVE file"
code: VALIDATION_INVALID_FORMAT
detail: "voice_references[0].audio is not valid reference audio: audio must be a RIFF/WAVE file"
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
reference_text_missing:
summary: نص المرجع مفقود أو مكوّن من مسافات فقط
value:
error: voice_references[0].text must contain the reference transcript
code: VALIDATION_REQUIRED_FIELD
detail: voice_references[0].text must contain the reference transcript
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
invalid_voice_id:
summary: voice_id موجود لكنه ليس UUID صالحًا
value:
error: voice_id must be a valid UUID
code: VALIDATION_INVALID_UUID
detail: voice_id must be a valid UUID
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
voice_id_not_found:
summary: voice_id صالح البنية (UUID) لكنه لا يحدد صوتًا متاحًا
value:
error: voice_id does not identify an available voice
code: TTS_VOICE_NOT_FOUND
detail: voice_id does not identify an available voice
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
input_not_allowed:
summary: نص رفضته سياسة محتوى TTS
value:
error: TTS input is not allowed
code: TTS_INPUT_NOT_ALLOWED
detail: TTS input is not allowed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `401`
غير مصرح
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
missing_key:
value:
error: Invalid authentication
code: AUTH_UNAUTHORIZED
detail: Invalid authentication
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `403`
لا يمنح مفتاح API صلاحية الوصول إلى قدرة الصوت المطلوبة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
scope_denied:
value:
error: scope not permitted
code: AUTH_FORBIDDEN
detail: scope not permitted
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `405`
الطريقة غير مسموحة
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
wrong_method:
value:
error: method not allowed
code: METHOD_NOT_ALLOWED
detail: method not allowed
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `413`
تجاوز جسم الطلب الحد المضبوط لهذا المسار (16 MiB لأجسام طلبات TTS).
وهذا الفشل غير قابل لإعادة المحاولة بالحجم نفسه؛ أرسل طلبًا أصغر.
ولا تحمل صورة جسم الطلب من هذه الاستجابة أي كائن `data`. أما المسارات الصوتية
الثلاثة فتجيب على الجسم المفرط في الحجم بالحالة والرمز نفسيهما لكنها تتضمن
`data`؛ راجع توثيق `413` الخاص بها.
كما يجيب `POST /http/tts` بهذه الحالة عندما يتجاوز الصوت المرجعي بعد فك الترميز
سقف البايتات لكل مرجع في النشر (الافتراضي 2 MiB)، وتلك الصورة تحمل `data` مع
`bound` بقيمة `tts_voice_reference_bytes` و`unit` بقيمة `bytes`. ويُفحص ذلك من
طول base64 قبل فك ترميز الحمولة، لذلك لا يُنشأ المرجع المفرط في الحجم أبدًا.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
body_too_large:
value:
error: request body too large
code: PAYLOAD_TOO_LARGE
detail: request body too large
retryable: false
timestamp: 2026-01-15T10:30:00Z
voice_reference_too_large:
summary: الصوت المرجعي بعد فك الترميز يتجاوز سقف البايتات لكل مرجع
value:
error: voice_references[0].audio decodes to 3145728 bytes; limit is 2097152
code: PAYLOAD_TOO_LARGE
detail: voice_references[0].audio decodes to 3145728 bytes; limit is 2097152
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 2097152
observed: 3145728
unit: bytes
bound: tts_voice_reference_bytes
```
### الاستجابة `422`
حُلِّل الطلب بصورة صحيحة وكل حقل فيه صالح على حدة، لكن وحدة عمل دلالية
تتجاوز سقفها (RFC 9110 15.5.21). فبضع مئات من البايتات من النص قد تطلب عمل
تصنيع أكبر بكثير مما يشير إليه حجمها، ولذلك لا يمكن التعبير عن هذه الحدود بسقف
بايتات ولا تكون أبدًا الحالة `413`.
ويسمّي `data.bound` السقف الذي تم بلوغه:
* `tts_input_characters` — `text` أطول من حد أحرف فئة الحساب (الافتراضيات: 500
للمجاني، و1,000 للقياسي والمؤسسي).
* `tts_voice_reference_text_characters` — `voice_references[0].text` أطول من حد
نص المرجع (الافتراضي 500).
* `tts_voice_reference_count` — أكثر من عنصر واحد في `voice_references`؛
و`maxItems` المنشور هو 1.
* `tts_voice_reference_duration` — الصوت المرجعي بعد فك الترميز أطول من سقف
النشر (الافتراضي 15 ثانية)، وهو مطابق لحد المرجع في النموذج المنشور نفسه.
و`data.observed` بالثواني الكاملة، مقرَّبًا إلى الأعلى.
وكل واحد من هذه يُفحص قبل أي بحث عن نموذج أو قبول أو محاسبة، لذلك لا يستهلك
الطلب المرفوض أي حصة ولا أي خانة تزامن. وهو غير قابل لإعادة المحاولة: فإعادة
إرسال الطلب نفسه لا يمكن أن تنجح.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
text_too_long:
summary: النص يتجاوز الحد الافتراضي للفئة المجانية في وقت التشغيل
value:
error: TTS input contains 501 characters; limit is 500
code: CHARACTER_COUNT_EXCEEDED
detail: TTS input contains 501 characters; limit is 500
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 500
observed: 501
unit: characters
bound: tts_input_characters
reference_text_too_long:
summary: نص المرجع يتجاوز حده المستقل الخاص
value:
error: voice_references[0].text contains 501 characters; limit is 500
code: CHARACTER_COUNT_EXCEEDED
detail: voice_references[0].text contains 501 characters; limit is 500
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 500
observed: 501
unit: characters
bound: tts_voice_reference_text_characters
too_many_voice_references:
summary: أكثر من maxItems المنشور وقيمته 1
value:
error: voice_references contains 2 references; limit is 1
code: VOICE_REFERENCE_COUNT_EXCEEDED
detail: voice_references contains 2 references; limit is 1
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 1
observed: 2
unit: references
bound: tts_voice_reference_count
reference_audio_too_long:
summary: مقطع مرجعي أطول من حد المرجع في النموذج المنشور
value:
error: voice_references[0].audio is 16 seconds long; limit is 15
code: AUDIO_DURATION_EXCEEDED
detail: voice_references[0].audio is 16 seconds long; limit is 15
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
data:
limit: 15
observed: 16
unit: seconds
bound: tts_voice_reference_duration
```
### الاستجابة `429`
لدى الحساب فعلًا من العمليات المتزامنة من هذا النوع قيد التنفيذ ما
تسمح به خطته، محسوبة عبر كل نسخة من الخادم (SAU-2181). والحد لكل حساب قابل
للفوترة، لذلك تتشارك عدة مفاتيح API تابعة لحساب واحد حصة واحدة، وإنشاء مفاتيح
أكثر لا يرفعها. ولكل نوع عمل حصته الخاصة، لذلك لا يتنافس ASR الفوري وTTS أحدهما
مع الآخر.
وهذه الحالة قابلة لإعادة المحاولة وتزول عادة في ثوان، بمجرد انتهاء إحدى عمليات
الحساب الجارية. التزم بترويسة `Retry-After`.
ولا تخلط بينها وبين الحالة 429 الأخرى على هذه المسارات: فحد معدل الطلبات لكل
مفتاح في البوابة يبلّغ `RATE_LIMIT_EXCEEDED`، وسقف جلسات HTTP لكل اتصال يبلّغ
`SESSION_SLOTS_EXHAUSTED`. ويميز بينها حقل `code`. ولا يستهلك الرفض أي رصيد
ولا أي حصة.
**الترويسات:**
```yaml
Retry-After:
description: عدد الثواني التي يجب انتظارها قبل إعادة المحاولة.
schema:
type: integer
examples:
- 5
```
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
account_concurrency_exhausted:
value:
error: too many concurrent operations for this account
code: CONCURRENCY_LIMIT_EXCEEDED
detail: too many concurrent operations for this account
retryable: true
timestamp: 2026-01-15T10:30:00Z
data:
limit: 4
observed: 4
unit: operations
bound: account_concurrency_tts
```
### الاستجابة `500`
فشل TTS قبل تثبيت الخرج الثنائي. وإذا كان الخرج قد ثُبِّت فعلًا، ينتهي بث `200`
الثنائي الجزئي من دون إلحاق خطأ JSON.
وتحمل هذه الحالة رمزين متمايزين. `TTS_SYNTHESIS_FAILED` هو الحالة القابلة لإعادة
المحاولة: فشل في حل النموذج أو السعة أو الاستدلال قد تزيله محاولة لاحقة.
و`TTS_VOICE_RESOLUTION_FAILED` (SAU-2258) غير قابل لإعادة المحاولة: صوت محلول
بياناته المخزَّنة ناقصة أو تالفة (صوت أو نص مفقود، أو URI مخزَّن غير قابل
للاستخدام، أو صوت ليس PCM بترميز INT16)، أو خطأ قاعدة بيانات/تخزين غير مصنَّف.
وإعادة إرسال الطلب نفسه لا يمكن أن تصلح بيانات صوت معطوبة من جهة الخادم.
ولا تصل إلى هنا حالات فشل التحقق من النص ومن المرجع الصوتي: فهي تُبلَّغ بالحالة
`400` أو `413` أو `422` برمز محدد قبل أن يبدأ التصنيع. كما أن `voice_id`
المُرسَل من العميل إذا كان غير صالح أو غير معروف فليس هنا أيضًا — بل هو `400`
(`VALIDATION_INVALID_UUID` / `TTS_VOICE_NOT_FOUND`)؛ وانقطاع قاعدة بيانات/تخزين
مثبت أثناء حل الصوت هو `503` (`SERVER_DEPENDENCY_FAILURE`، قابل لإعادة المحاولة).
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
synthesis_failed:
summary: فشل نموذج/سعة/استدلال قابل لإعادة المحاولة
value:
error: TTS synthesis failed
code: TTS_SYNTHESIS_FAILED
detail: TTS synthesis failed
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
voice_resolution_failed:
summary: الصوت المحلول بياناته المخزَّنة ناقصة أو تالفة (غير قابل لإعادة المحاولة)
value:
error: selected voice could not be resolved
code: TTS_VOICE_RESOLUTION_FAILED
detail: selected voice could not be resolved
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: false
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `503`
إحدى التبعيات المطلوبة غير متاحة مؤقتًا. والاستجابة قابلة لإعادة المحاولة:
فقد ينجح الطلب نفسه بعد تعافي تلك التبعية.
تعني `TTS_MODERATION_UNAVAILABLE` أن جهة الإشراف على المحتوى لم تتمكن من اتخاذ
قرار، ولذلك فشل التوليف بصورة مغلقة. وهي متمايزة عمدًا عن
`TTS_INPUT_NOT_ALLOWED`: فلا ينبغي الإبلاغ عن فشل البنية التحتية بوصفه رفضًا
للسياسة.
تمثل `SERVER_DEPENDENCY_FAILURE` انقطاعًا عابرًا مصنَّفًا إيجابيًا لقاعدة
بيانات أو تخزين كائنات أثناء حل `voice_id` (SAU-2258). وهي متمايزة عن
`500 TTS_VOICE_RESOLUTION_FAILED`، التي تحدد بيانات صوت معطوبة من جهة الخادم
لا تصلحها إعادة المحاولة. ويجري الفحصان قبل أي خصم حصة أو رسم حد معدل أو
استدلال، ولذلك لا يُحاسب الطلب المُعاد مرتين.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
voice_resolution_unavailable:
summary: انقطاع عابر لقاعدة البيانات/التخزين أثناء حل الصوت
value:
error: voice resolution is temporarily unavailable
code: SERVER_DEPENDENCY_FAILURE
detail: voice resolution is temporarily unavailable
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
moderation_unavailable:
summary: جهة الإشراف على المحتوى غير متاحة مؤقتًا
value:
error: TTS moderation is unavailable
code: TTS_MODERATION_UNAVAILABLE
detail: TTS moderation is unavailable
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
### الاستجابة `504`
انقضت مهلة التصنيع غير القابلة لإعادة الضبط والبالغة 25 ثانية قبل توفر نتيجة
نهائية كاملة على مستوى البروتوكول. هذه الاستجابة قابلة لإعادة المحاولة ولا
تُعاد إلا عندما لا يكون الخرج الثنائي قد بدأ؛ وإلا فينتهي البث الثنائي الجزئي
من دون إلحاق JSON.
#### نوع المحتوى: `application/json`
**المخطط:**
```yaml
type: object
required:
- error
- code
- retryable
- timestamp
properties:
error:
type: string
description: معرّف الخطأ القديم، مثبت للتوافق مع الإصدارات السابقة
message:
type: string
description: حقل الرسالة القديم، ويوجد فقط عند غياب مفتاح المصادقة
code:
type: string
description: |-
رمز خطأ قابل للقراءة آليًا. هذه القائمة هي المجموعة التي يمكن بلوغها عبر
مسارات HTTP الأربعة في هذا المستند. أما واجهة Socket.IO فتصدر مجموعة مختلفة
تشمل `SERVER_INTERNAL` و`RATE_LIMIT_EXCEEDED` و`RATE_LIMIT_SERVICE_BUSY`
و`TTS_MODEL_NOT_FOUND` و`TTS_VOICE_LIST_FAILED`؛ راجع مستندات AsyncAPI.
وللحالة `429` على هذه المسارات مصدران متمايزان: حد معدل الطلبات لكل مفتاح
في البوابة، وهو يبلّغ `RATE_LIMIT_EXCEEDED` وشكل جسمه يعتمد على النشر، وتحكم
القبول في الخدمة نفسها، وهو يبلّغ `CONCURRENCY_LIMIT_EXCEEDED` أو
`SESSION_SLOTS_EXHAUSTED` أو `SESSION_BYTE_RATE_EXCEEDED` بهذا المخطط ومع
ترويسة `Retry-After`.
ولا يمكن بلوغ رموز `SESSION_*` إلا على مسارَي الزمن الفوري المتعددَي POST،
اللذين يحفظان شبه جلسة مفتاحية عبر الطلبات: فـ`SESSION_BYTES_EXCEEDED` هو
`413`، و`SESSION_DURATION_EXCEEDED` و`AUDIO_DURATION_EXCEEDED` هما `422`،
و`SESSION_IDLE_TIMEOUT` هو `408`، و`SESSION_EXPIRED` هو `409`،
و`SESSION_SLOTS_EXHAUSTED` و`SESSION_BYTE_RATE_EXCEEDED` هما `429`.
و`CHARACTER_COUNT_EXCEEDED` و`VOICE_REFERENCE_COUNT_EXCEEDED` هما `422` ولا
يمكن بلوغهما إلا على `POST /http/tts`. وكلاهما يحمل `data`. ويميز `data.bound`
بين سقفَي الأحرف: `tts_input_characters` لـ`text`، و
`tts_voice_reference_text_characters` لـ`voice_references[0].text`. وعلى
المسار نفسه يبلّغ `AUDIO_DURATION_EXCEEDED` مع `data.bound` بقيمة
`tts_voice_reference_duration` عن صوت مرجعي أطول من سقف النشر، ويبلّغ
`PAYLOAD_TOO_LARGE` مع `data.bound` بقيمة `tts_voice_reference_bytes` عن صوت
مرجعي يتجاوز حجمه بعد فك الترميز ذلك السقف.
ويبلّغ `POST /http/tts` أيضًا عن نتائج حل `voice_id` (SAU-2258):
`VALIDATION_INVALID_UUID` (`400`) لـ`voice_id` مشوّه، و`TTS_VOICE_NOT_FOUND`
(`400`) لـ`voice_id` صالح البنية لكنه لا يحدد صوتًا متاحًا،
و`TTS_VOICE_RESOLUTION_FAILED` (`500`، غير قابل لإعادة المحاولة) لصوت محلول
بياناته المخزَّنة ناقصة أو تالفة، و`SERVER_DEPENDENCY_FAILURE` (`503`، قابل
لإعادة المحاولة) لانقطاع قاعدة بيانات/تخزين عابر مصنَّف إيجابيًا أثناء الحل.
ويبلغ حارس المحتوى فيه عن `TTS_INPUT_NOT_ALLOWED` (`400`، غير قابل لإعادة
المحاولة) عندما ترفض السياسة النص، وعن `TTS_MODERATION_UNAVAILABLE`
(`503`، قابل لإعادة المحاولة) عندما يتعذر على الإشراف اتخاذ قرار ويفشل
التوليف بصورة مغلقة.
enum:
- AUTH_UNAUTHORIZED
- AUTH_FORBIDDEN
- VALIDATION_INVALID_LANGUAGE
- VALIDATION_INVALID_FORMAT
- VALIDATION_REQUIRED_FIELD
- VALIDATION_FILE_CORRUPT
- VALIDATION_INVALID_PARAM
- VALIDATION_INVALID_UUID
- PAYLOAD_TOO_LARGE
- AUDIO_DURATION_EXCEEDED
- CHARACTER_COUNT_EXCEEDED
- VOICE_REFERENCE_COUNT_EXCEEDED
- SESSION_BYTES_EXCEEDED
- SESSION_DURATION_EXCEEDED
- SESSION_IDLE_TIMEOUT
- SESSION_EXPIRED
- SESSION_SLOTS_EXHAUSTED
- SESSION_BYTE_RATE_EXCEEDED
- CONCURRENCY_LIMIT_EXCEEDED
- ASR_UNSUPPORTED_CODEC
- ASR_TRANSCRIPTION_FAILED
- ASR_MODEL_NOT_FOUND
- TTS_SYNTHESIS_FAILED
- TTS_DEADLINE_EXCEEDED
- TTS_VOICE_NOT_FOUND
- TTS_VOICE_RESOLUTION_FAILED
- TTS_INPUT_NOT_ALLOWED
- TTS_MODERATION_UNAVAILABLE
- SERVER_DEPENDENCY_FAILURE
- DIARIZATION_FAILED
- DIARIZATION_MODEL_NOT_FOUND
- METHOD_NOT_ALLOWED
detail:
type: string
description: شرح خطأ مقروء للبشر
job_id:
type: string
format: uuid
description: UUID الارتباط عند توفره؛ وفي مسارات البث يكون هذا UUID التدفق رغم اسم الحقل القديم
retryable:
type: boolean
description: ما إذا كان ينبغي للعميل إعادة محاولة الطلب
timestamp:
type: string
format: date-time
description: طابع زمني وفق ISO 8601 لوقت وقوع الخطأ
data:
type: object
description: |-
موجود فقط في حالات رفض الحدود. يسمّي الحد الذي تم تجاوزه وقيمته
المضبوطة والقيمة المرصودة، حتى يعرف العميل أي حد بلغه دون تحليل نص.
required:
- limit
- observed
- unit
- bound
properties:
limit:
type: integer
format: int64
description: القيمة المضبوطة للحد
observed:
type: integer
format: int64
description: القيمة المرصودة عند رفض الطلب
unit:
type: string
description: وحدة `limit` و`observed`
examples:
- operations
bound:
type: string
description: معرّف الحد الذي تم تجاوزه
examples:
- account_concurrency_tts
```
**الأمثلة:**
```yaml
deadline_exceeded:
value:
error: TTS synthesis deadline exceeded
code: TTS_DEADLINE_EXCEEDED
detail: TTS synthesis deadline exceeded
job_id: 7f51f2c2-e7bc-41c8-a850-f848df2ddfc8
retryable: true
timestamp: 2026-01-15T10:30:00Z
```
## الخطوات التالية
استجابة HTTP المباشرة تسجيل بروتوكول بلا فواصل، وليست PCM خامًا قابلاً للاستعادة ولا WAV. لا تضف إليها ترويسة WAV. للخرج القابل للتشغيل، استخدم مسار SDK المنشورة عبر Socket.IO، ولا تضف ترويسة WAV إلا بعد جمع حمولة PCM النهائية التي فكها SDK.
### [أنشئ ملف WAV](/ar/recipes/text-to-speech-to-file)
شغّل وصفة SDK المختبرة للإصدار `0.18.0` وحوّل ناتج PCM16 المكتمل.
### [افهم تسجيل HTTP](/ar/api-guides/realtime-http)
راجع غياب فاصل الإطارات والخرج غير المكتمل والمهل وقيود التنظيف.
### [نفّذ TTS عبر SDK](/ar/api-guides/socketio)
استخدم وسيلة Socket.IO المنشورة لدورة حياة تدفق مدعومة.