# Errors URL: /api-reference/errors Reference for every error type returned by Soniox APIs (REST, async, STT WebSocket, TTS WebSocket, TTS REST), with the cause and how to resolve each one. import { Callout } from "@/components/callout"; import { Badge } from "@openapi/ui/components/method-label"; ## Overview This page documents errors from every Soniox API surface: * **REST API** at `api.soniox.com`: synchronous endpoints for files, transcriptions, speakers, usage logs, temporary API keys, and async transcription submission. * **Async transcription failure**: a job created via `POST /v1/transcriptions` returned `200`, but the transcription itself ends in `status: "failed"` after the audio is downloaded or transcribed. * **STT WebSocket** at `stt-rt.soniox.com`: real-time speech-to-text. * **TTS WebSocket** at `tts-rt.soniox.com/tts-websocket`: real-time text-to-speech. * **TTS REST** at `tts-rt.soniox.com/tts`: single-request text-to-speech. All surfaces share one `error_type` taxonomy. Branch your client code on `error_type`, not on the human-readable message; the wording may change, the slug will not. Every error response carries: * `error_type`: stable, machine-readable identifier. See [API error types](#api-error-types) for the full list. * `request_id`: unique per request. Include it when contacting [support@soniox.com](mailto:support@soniox.com); server logs are keyed on it. * `more_info`: a URL pointing at the section on this page describing the `error_type`. The pattern is `https://soniox.com/docs/api-reference/errors#` with underscores replaced by hyphens. The HTTP status code mapped to each `error_type` is the same on every surface. *** ## Response structure ### REST API response REST API errors return a JSON body with the HTTP status code: ```json { "status_code": 401, "error_type": "unauthenticated", "message": "Incorrect API key provided. You can get an API key at https://console.soniox.com", "validation_errors": [], "request_id": "3d37a3bd-5078-47ee-a369-b204e3bbedda", "more_info": "https://soniox.com/docs/api-reference/errors#unauthenticated" } ``` HTTP status code, mirrored in the response body for convenience. Stable, machine-readable identifier of the error. Branch on this, not on `message`. See the [error reference](#api-error-types) below for the full list. Human-readable description of the error. Safe to show to operators or log; do not parse or pattern-match against it. Populated when `error_type` is `invalid_request` and the cause is a per-field validation failure. Each entry has `error_type`, `location` (dotted path of the offending field), and `message`. Unique identifier of this request. Server logs are keyed on it, so include it when contacting [support@soniox.com](mailto:support@soniox.com). Link to the section on this page describing the `error_type`. The URL pattern is `https://soniox.com/docs/api-reference/errors#` with underscores replaced by hyphens. ### Async transcription failure When you create a transcription with `POST /v1/transcriptions`, the call returns `200` and a transcription object as soon as the job is accepted. The work itself happens asynchronously: the audio is downloaded (if a URL was supplied), then transcribed. If the **job** fails, the HTTP layer doesn't see the failure. Instead, `GET /v1/transcriptions/{id}` returns `status: "failed"` with `error_type` and `error_message` fields populated. Always check `status` and read these fields when polling a transcription. ```json { "id": "84c32fc6-4fb5-4e7a-b656-b5ec70493753", "status": "failed", "error_type": "file_download_failed", "error_message": "Failed to download audio from the provided URL.", "...": "..." } ``` Failed async jobs are **not auto-retried**. Fix the cause and submit a new transcription. The `error_type` values that can appear on a failed job are flagged below with **Async** on their **Surfaces** line. ### Voice processing failure When you create a voice with `POST /v1/voices`, the call returns `201` as soon as the reference clip is accepted. The voice is then processed for each Text-to-Speech model asynchronously, so a per-model failure is not visible to the HTTP layer. Instead, `GET /v1/voices/{id}` reports a per-model status in the `models` array. A model the voice failed to process for has `status: "failed"` with `error_type` and `error_message` populated: ```json { "id": "21b9c8e2-1c3a-4d5e-9f8a-123456789abc", "name": "narrator", "models": [ { "model": "tts-rt-v2", "status": "failed", "error_type": "voice_audio_too_long", "error_message": "The reference audio clip is too long for this model. Upload a shorter clip." } ] } ``` A failure is **terminal and not auto-retried**. Fix the reference clip and create a new voice. The `error_type` values that can appear here are flagged below with **Voice** on their **Surfaces** line. Using a voice for a model whose status is not `ready` returns an HTTP error at stream start (see [`voice_not_ready`](#voice-not-ready), [`voice_not_prepared`](#voice-not-prepared), and [`voice_failed`](#voice-failed)). ### STT WebSocket error frame On error, the STT WebSocket sends a single JSON text frame and then closes the connection with WebSocket close code `1000` (Normal Closure). Branch on `error_type` inside the frame, not on the close code. ```json { "tokens": [], "error_code": 401, "error_type": "unauthenticated", "error_message": "Incorrect API key provided. You can get an API key at https://console.soniox.com", "more_info": "https://soniox.com/docs/api-reference/errors#unauthenticated", "request_id": "3d37a3bd-5078-47ee-a369-b204e3bbedda" } ``` The error frame reuses the shape of a normal response frame (hence the empty `tokens` array), with the error fields populated. `error_code` is the HTTP status as an integer, and the human-readable text lives in `error_message` rather than `message`. The frame does not carry a `validation_errors` array; a single failure is described in `error_message`. ### TTS WebSocket error frame The TTS WebSocket multiplexes multiple streams over a single connection. Every error frame carries a `stream_id`: ```json { "stream_id": "stream-1", "error_code": 400, "error_type": "invalid_stream_state", "error_message": "Stream stream-1 is already active on this connection. Choose a different stream_id, or cancel the existing stream first.", "more_info": "https://soniox.com/docs/api-reference/errors#invalid-stream-state", "request_id": "3d37a3bd-5078-47ee-a369-b204e3bbedda" } ``` **Per-stream errors do not close the connection.** Other streams on the same connection continue running and the client may keep using the WebSocket. A `{"terminated": true, "stream_id": "..."}` frame typically follows for the affected stream. Connection-level errors (malformed top-level message, server shutting down) carry `stream_id: ""` and close the connection. ### TTS REST response TTS REST has two error paths depending on whether response headers have been sent. **Headers not yet sent.** Validation and authentication errors, as well as errors raised before audio streaming starts, return a JSON body with the HTTP status code: ```http HTTP/1.1 401 Unauthorized Content-Type: application/json { "error_code": 401, "error_type": "unauthenticated", "error_message": "Missing API key. Provide it as an Authorization header (e.g. 'Authorization: Bearer '). You can get an API key at https://console.soniox.com.", "more_info": "https://soniox.com/docs/api-reference/errors#unauthenticated", "request_id": "3d37a3bd-5078-47ee-a369-b204e3bbedda" } ``` **Headers already sent (mid-stream failure).** The initial response was `200 OK` and audio bytes have already been flushed to the client. The connection closes abruptly with no in-band error payload. Clients should treat a truncated audio stream as a server-side failure. The exception is [`max_audio_duration_reached`](#max-audio-duration-reached), where the response ends cleanly with truncated audio. *** ## API error types Each section below documents one `error_type`. The badge shows the HTTP status code (the same on every surface), and the **Surfaces** line lists every API where this `error_type` can appear. ### `invalid_request` HTTP 400 **Surfaces:** [REST](#rest-api-response) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The request body or query parameters failed validation. Common triggers: * **REST:** a required field is missing, a value is out of range, an enum value is unknown, a multipart upload is malformed or has unknown size, an uploaded file exceeds the per-file byte limit, or a request-level invariant is violated (for example, `end_time` not strictly after `start_time` on `GET /v1/usage-logs`). * **WebSocket / TTS REST:** a required start-request or per-stream field is missing or too long, a JSON message is malformed, an audio frame is not valid base64, a translation parameter combination is invalid, `speed` is outside the supported range (between `0.7` and `1.3`), or `reduce_silence` is enabled on a model that does not support it. * **STT WebSocket:** the `context` object exceeds the [context size limit](/stt/concepts/context#context-size-limit) of 8,000 tokens. When the cause on REST is a per-field validation failure, the response includes `validation_errors` with the exact `location` and reason for each field: ```json { "status_code": 400, "error_type": "invalid_request", "message": "Invalid request.", "validation_errors": [ { "error_type": "missing", "location": "file.file", "message": "Field required" } ], "request_id": "..." } ``` WebSocket and TTS REST responses do not carry `validation_errors`; the single failure is described in `error_message`. **Solution.** Read `validation_errors` (REST) or `error_message` (streaming) and resend the request with corrected values. ### `invalid_cursor` HTTP 400 **Surfaces:** [REST](#rest-api-response) **Cause.** The `cursor` query parameter on a paginated endpoint (`/v1/files`, `/v1/transcriptions`, `/v1/usage-logs`) could not be decoded. The cursor is opaque and only valid when copied verbatim from the previous page's `next_page_cursor`; any modification, truncation, or stale cursor triggers this error. **Solution.** Omit `cursor` to start from the first page, or pass the exact `next_page_cursor` from the previous response without modification. Keep all other query parameters constant across pages of the same listing. ### `model_not_available` HTTP 400 **Surfaces:** [REST](#rest-api-response) · [Async](#async-transcription-failure) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The requested `model` is unknown, has been retired, or is not enabled for the calling project or region. **Solution.** Use a model from the [STT models catalog](/stt/models) or [TTS models catalog](/tts/models). If you've been pinning a specific model, switch to a current one before its retirement date. ### `max_concurrent_streams_reached` HTTP 400 **Surfaces:** [TTS WebSocket](#tts-websocket-error-frame) **Cause.** The TTS WebSocket connection has reached its server-imposed cap on the number of simultaneous streams it can run. This is a per-connection limit and is **not** the per-organization or per-project concurrency cap (which surfaces as [`limit_exceeded`](#limit-exceeded)). **Solution.** Send a `cancel` message for one of the active streams on this connection to free a slot, or open a new WebSocket connection. ### `invalid_stream_state` HTTP 400 **Surfaces:** [TTS WebSocket](#tts-websocket-error-frame) **Cause.** A request was issued against a stream that is in the wrong state for that operation. Concrete cases: * `start` with a `stream_id` that is already active on the connection. * `text` or `cancel` for a `stream_id` that does not exist. * `text` or `text_end` after the stream already received `text_end`. * `cancel` after the stream was already cancelled. **Solution.** Read `error_message` for the specific state issue. Most cases indicate a client-side bug; verify the stream lifecycle follows `start` → `text…` → `text_end` (or `cancel` from any state). ### `invalid_audio_file` HTTP 400 **Surfaces:** [REST](#rest-api-response) (`POST /v1/files` upload) · [Async](#async-transcription-failure) **Cause.** The audio could not be decoded, contains no audio stream, or exceeds the model's maximum audio duration. For async jobs this is set during the download / convert step or during the transcribe step's duration recheck. **Solution.** Try transcribing the file directly in the [Soniox Console](https://console.soniox.com) to confirm whether the file itself is the problem. If it is, re-encode to a supported container/codec or split long audio into shorter segments. See the [supported audio formats](/stt/async/async-transcription#audio-formats). ### `unauthenticated` HTTP 401 **Surfaces:** [REST](#rest-api-response) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The request did not authenticate. The `Authorization` header was missing, or the API key was malformed, revoked, expired, scoped to a different environment, or longer than 256 characters. Temporary API keys can also fail here when they are expired, single-use and already consumed, or used for an action they were not issued for. **Solution.** Pass a valid key as `Authorization: Bearer ` on REST and TTS REST, or in the `api_key` field of the start message on the WebSocket APIs. Get or rotate API keys in the [Soniox Console](https://console.soniox.com). For client apps, use a [temporary API key](/guides/temporary-api-keys). ### `permission_denied` HTTP 403 **Surfaces:** [REST](#rest-api-response) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The API key is valid, but it does not have the permission this call needs. Each key has a list of permissions, and some have a Read and a Write level: a Read key is refused on calls that create, change or delete. Creating a temporary API key needs both the **Temporary API keys** permission and the permission for the service in `usage_type`. **Solution.** Edit the key's permissions in the [Soniox Console](https://console.soniox.com), or use a key that has the permission. A change can take a few minutes to apply. See [API key permissions](/guides/api-key-permissions) for what each permission allows. ### `organization_balance_exhausted` HTTP 402 **Surfaces:** [REST](#rest-api-response) · [Async](#async-transcription-failure) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The available balance has dropped to zero. Raised before the request runs, and also evaluated when an async job is about to start downloading or transcribing. In the async case the job moves to `failed` with this `error_type`. **Solution.** Top up at [Billing overview](https://console.soniox.com/org/billing/overview/) or enable autopay. Failed async jobs are not auto-retried; resubmit after funding. ### `organization_monthly_budget_exhausted` HTTP 402 **Surfaces:** [REST](#rest-api-response) · [Async](#async-transcription-failure) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The organization has hit its configured monthly budget cap (`monthly_budget_usd`). Resets at the start of the next calendar month. **Solution.** Raise the cap on the [organization limits](https://console.soniox.com/org/limits/) page, or wait for the month to roll over. ### `project_monthly_budget_exhausted` HTTP 402 **Surfaces:** [REST](#rest-api-response) · [Async](#async-transcription-failure) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The project has hit its configured monthly budget cap. **Solution.** Raise the cap on the [project limits](https://console.soniox.com/org/projects/limits/) page, or wait for the month to roll over. ### `file_download_blocked` **Surfaces:** [Async](#async-transcription-failure) (failed transcription, no HTTP error) **Cause.** The supplied `audio_url` could not be fetched for safety reasons: the URL resolved to a private or otherwise blocked IP (SSRF guard). **Solution.** Use a publicly reachable URL whose host resolves to a routable IP. If the project or organization was deleted, recreate it (or use a different one) and resubmit. ### `file_download_failed` **Surfaces:** [Async](#async-transcription-failure) (failed transcription, no HTTP error) **Cause.** Fetching `audio_url` failed: HTTP error (4xx / 5xx), DNS failure, TLS failure, connection timeout, or the server closed the connection mid-stream. 4xx responses are not retried; other transient failures are retried internally up to a bound before the job is marked as failed. **Solution.** Make the URL reachable and stable. For files you control, prefer uploading via `POST /v1/files` rather than relying on a remote URL. ### `transcription_output_too_long` **Surfaces:** [Async](#async-transcription-failure) (failed transcription, no HTTP error) **Cause.** The transcription completed but produced more output than the model is allowed to return in a single job. Not expected to occur in normal use. If you see this `error_type`, please contact [support@soniox.com](mailto:support@soniox.com) with the transcription ID. ### `file_not_found` HTTP 404 **Surfaces:** [REST](#rest-api-response) · [Async](#async-transcription-failure) **Cause.** No file with the given ID exists in the project the API key belongs to. Returned for IDs that never existed, IDs that were deleted, and IDs that exist but belong to a different project. Soniox does not leak cross-project existence. On async jobs it means the file referenced by `file_id` was deleted after the transcription was created but before it started processing. **Solution.** Confirm the ID by listing files via `GET /v1/files`, and make sure the API key is scoped to the project that owns the file. Keep an uploaded file until the transcription that uses it reaches a terminal state (`completed` or `error`), then delete it. ### `transcription_not_found` HTTP 404 **Surfaces:** [REST](#rest-api-response) **Cause.** No transcription with the given ID exists in the caller's project. Same semantics as [`file_not_found`](#file-not-found): deleted, never existed, or belongs to a different project. **Solution.** Confirm the ID with `GET /v1/transcriptions`, and check that the API key is scoped to the project that owns the transcription. ### `voice_not_found` HTTP 404 **Surfaces:** [REST](#rest-api-response) (`GET`/`DELETE /v1/voices/{id}`, `POST /v1/voices/{id}/recompute`) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** No voice with the given ID exists in the calling project. Returned for IDs that never existed, were deleted, or belong to a different project; Soniox does not leak cross-project existence. On the TTS APIs this is raised at stream start when the `voice` field is a UUID that does not resolve to a voice in the project. **Solution.** Confirm the ID with `GET /v1/voices`, and make sure the API key is scoped to the project that owns the voice. To use a built-in voice instead, pass its name (for example `Adrian`); see [voices](/tts/concepts/voices). ### `voice_name_conflict` HTTP 409 **Surfaces:** [REST](#rest-api-response) (`POST /v1/voices`) **Cause.** A voice with the same `name` already exists in the project. Voice names are unique per project. **Solution.** Choose a different name, or delete the existing voice with `DELETE /v1/voices/{id}` first. ### `voice_not_prepared` HTTP 409 **Surfaces:** [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The voice exists but has not been prepared for the requested `model`, so it cannot be used with it yet. This typically happens when a model is released after the voice was created: the voice reports `status: "not_computed"` for that model. **Solution.** Call `POST /v1/voices/{id}/recompute` (optionally with a `model`) to prepare the voice for the model, poll `GET /v1/voices/{id}` until that model's status is `ready`, then retry the request. ### `voice_not_ready` HTTP 503 **Surfaces:** [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The voice is still being processed for the requested model (per-model status `processing`). This is transient: processing starts right after the voice is created or recomputed and usually finishes within seconds. **Solution.** Retry after a short delay, or poll `GET /v1/voices/{id}` until the model's status is `ready` before starting the stream. ### `voice_failed` HTTP 503 **Surfaces:** [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** Processing the voice failed permanently for the requested model, so the voice cannot be used with it. Despite the 503 status this is **terminal, not retryable**. Inspect the voice's `models[].error_type` and `error_message` via `GET /v1/voices/{id}` for the underlying reason (for example [`voice_audio_too_long`](#voice-audio-too-long) or [`voice_invalid_audio`](#voice-invalid-audio)). **Solution.** Create a new voice from a valid reference clip. Recompute does not recover a voice that has terminally failed. ### `voice_audio_too_long` **Surfaces:** [Voice](#voice-processing-failure) (failed voice processing, no HTTP error) **Cause.** The reference audio clip is longer than the model allows (currently a maximum of 2 minutes). Clip duration is not checked at upload time, so this surfaces as a per-model processing failure rather than an upload error. **Solution.** Create a new voice from a shorter clip (at most 2 minutes). ### `voice_invalid_audio` **Surfaces:** [Voice](#voice-processing-failure) (failed voice processing, no HTTP error) **Cause.** The reference audio clip could not be processed. It may be in an unsupported format, corrupted, or contain no audio. **Solution.** Re-encode the clip to a supported audio format and create a new voice. ### `temp_api_key_session_expired` HTTP 403 **Surfaces:** [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The temporary API key in use was created with a `max_session_duration_seconds` cap, and that duration has elapsed for the current session. The temporary key itself may still be valid for new sessions (subject to its other limits); only the current session has been cut off. **Solution.** Create a new temporary API key (or use the same one if it has remaining uses) and start a new session. Long-running clients should refresh before the per-session cap rather than after. ### `request_timeout` HTTP 408 **Surfaces:** [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** A deadline was exceeded before the request could complete. Most common triggers: * **STT WebSocket: client too slow on audio.** The client failed to send audio chunks fast enough. For example, the initial chunk never arrived, or the decoder starved mid-stream. * **TTS WebSocket: client too slow on text.** After the config message, the client did not send any text within a few seconds, or paused more than a few seconds between text chunks without sending `text_end` to close the stream. Keepalive messages keep the connection open but do not extend this window. See [Connection keepalive](/tts/rt/connection-keepalive). **Solution.** Retry the request. For STT, ensure audio is streamed in real time or faster and that the first chunk is sent promptly after opening the connection. For TTS, send text chunks as soon as you have them and send `text_end` when the input is complete; if you do not know when the next text will arrive, end the stream and start a new one when it is ready. If the timeout persists across retries, contact [support@soniox.com](mailto:support@soniox.com) with the `request_id`. ### `transcription_invalid_state` HTTP 409 **Surfaces:** [REST](#rest-api-response) The transcription exists but is in a state that doesn't allow the requested operation. Read `message` for the specific reason. #### Not completed yet `GET /v1/transcriptions/{id}/transcript` while `status` is `queued`, `downloading`, or `transcribing`. **Solution.** Poll `GET /v1/transcriptions/{id}` until `status` is `completed`, or configure a webhook on the transcription to be notified. #### Failed The transcript was requested for a transcription that ended in `status: "failed"`. **Solution.** Read `error_type` and `error_message` from `GET /v1/transcriptions/{id}` to see why, and submit a new transcription after fixing the cause. #### No longer available Transcript data was retained for a limited window after completion and has since been purged. **Solution.** Re-submit the original audio as a new transcription. #### Cannot delete while processing `DELETE /v1/transcriptions/{id}` while `status` is `transcribing`. **Solution.** Wait for `status` to reach `completed` or `failed`, then retry the delete. ### `max_duration_reached` HTTP 413 **Surfaces:** [STT WebSocket](#stt-websocket-error-frame) **Cause.** The real-time connection reached the maximum allowed session duration (a fixed server-side cap) and was closed. This is a hard ceiling on how long a single WebSocket session may run, independent of any per-temporary-API-key cap (which surfaces as [`temp_api_key_session_expired`](#temp-api-key-session-expired)). Reconnecting on the same connection cannot extend it. **Solution.** Open a new WebSocket connection and resume streaming. For long-running capture, roll over to a fresh connection before the cap is reached rather than waiting for the server to close the session. ### `max_audio_duration_reached` HTTP 413 **Surfaces:** [TTS WebSocket](#tts-websocket-error-frame) **Cause.** Generated audio is capped at 2 minutes per request. When the cap is reached, generation stops and the audio output is truncated. This limit is fixed and cannot be increased. It is distinct from [`max_duration_reached`](#max-duration-reached), which caps the session duration of an STT WebSocket connection. On the **TTS WebSocket**, the final audio chunk is delivered without `audio_end`, followed by an error response and a `terminated` message for the stream: ```json { "error_code": 413, "error_type": "max_audio_duration_reached", "error_message": "The generated audio reached the maximum audio duration per request and the output was truncated. Synthesize the remaining text with a new request." } ``` The WebSocket connection stays open; other streams continue, and you can generate the remaining text on a new stream. On **TTS REST**, audio is streamed, so by the time the cap is reached the `200 OK` response is already committed and no error can be reported. The response simply ends with the truncated audio. **Solution.** Split long text into multiple requests, each below the [audio duration cap](/tts/rest-api/limits-and-quotas). On the WebSocket, start a new stream for the remaining text. ### `limit_exceeded` HTTP 429 **Surfaces:** [REST](#rest-api-response) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) A single `error_type` covers many distinct limits. Read `message` (REST) or `error_message` (streaming) to find out which one was hit. The sub-causes below are grouped by what kind of limit triggered the response. All current limits and your usage are visible in the [Soniox Console](https://console.soniox.com). Per-product reference: [Async STT](/stt/async/limits-and-quotas), [Real-time STT](/stt/rt/limits-and-quotas), [REST TTS](/tts/rest-api/limits-and-quotas), [Real-time TTS](/tts/rt/limits-and-quotas). #### Requests per minute (RPM) Too many calls of the same kind in a 60-second window, evaluated per organization or per project. RPM limits exist for: * WebSocket transcription * Async transcription * File management * Text-to-Speech * Temporary API key creation * Usage logs **Solution.** Slow down, batch where possible, or raise the limit in the console: [organization limits](https://console.soniox.com/org/limits/) or [project limits](https://console.soniox.com/org/projects/limits/). #### Concurrent requests Too many simultaneous in-flight requests on the organization or project. Applies to streaming workloads such as STT WebSocket, TTS WebSocket, and TTS REST. **Solution.** Reduce parallelism in the client, or request a higher concurrent-requests cap in the console. The TTS WebSocket also enforces a per-connection cap on simultaneous streams, which surfaces as the separate [`max_concurrent_streams_reached`](#max-concurrent-streams-reached) `error_type`. #### Total file count / total file size (GB) Adding this file would put the organization or project over its retained-storage cap (`files_total_count` or `files_total_size_gb`). **Solution.** Delete unused files via `DELETE /v1/files/{id}`, or raise the cap in the console. #### Pending file count Too many uploaded files are awaiting transcription (`transcribe_async_pending_num_files`). **Solution.** Wait for in-flight transcriptions to complete, then retry. #### Total transcription count / pending transcription count Analogous caps on the number of stored transcriptions (`transcribe_async_total_num_files`, `transcribe_async_pending_num_files`). **Solution.** Delete completed transcriptions with `DELETE /v1/transcriptions/{id}`, or raise the cap. ### `internal_error` HTTP 500 **Surfaces:** [REST](#rest-api-response) · [Async](#async-transcription-failure) · [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** Unhandled server-side exception, or an unrecoverable internal inconsistency. **Solution.** Retry once. If the error persists, contact [support@soniox.com](mailto:support@soniox.com) and include the `request_id` from the response. ### `service_unavailable` HTTP 503 **Surfaces:** [STT WebSocket](#stt-websocket-error-frame) · [TTS WebSocket](#tts-websocket-error-frame) · [TTS REST](#tts-rest-response) **Cause.** The service cannot accept the request right now. Concrete sub-causes include a backend model service being overloaded, encoder or decoder cache exhausted, the server gracefully shutting down, or no eligible model backend being available. The numeric `(code N)` in the message identifies the specific sub-cause for support triage. **Solution.** Retry with exponential backoff. The condition is transient; the retry will typically be routed to a healthy backend. If retries consistently fail, contact [support@soniox.com](mailto:support@soniox.com) with the `request_id` and the `(code N)` from the error message. *** ## Getting help If you can't determine the cause from `error_type` and `message`, or if an `internal_error` keeps recurring, contact [support@soniox.com](mailto:support@soniox.com) and include: * The `request_id` from the error response. * The `error_type` and `message` (or `error_message`). * The endpoint and HTTP method, or for async failures the transcription ID. * A short description of what you were trying to do.