Skip to main content
The enhancement endpoints run clarity-1 on a recording (REST) or on live audio (WebSocket). Each request does one task: noise_removal removes background noise and keeps the speech; target_speaker_extraction keeps the one person in a speaker sample you send and removes every other voice and sound. The output is always mono 16-bit PCM at 24 kHz, the same length as your input. All requests need an API key; see Authentication. Your organization also needs access to clarity-1. This page is the wire protocol. The SDKs wrap both endpoints (Python, JavaScript); the free month, the paid plan, the rate limits and what to do about each error are in the Speech enhancement guide.

Enhance a recording

Send a multipart/form-data upload.
string
required
clarity-1. Any other value is rejected.
file
required
The recording, as a WAV file. At most 300 seconds, and at most 64 MB for the whole request.
string
default:"noise_removal"
noise_removal or target_speaker_extraction.
file
Required for target_speaker_extraction, rejected for noise_removal. A WAV sample of the person to keep, 2–8 seconds long. See A good speaker sample.
number
How many seconds the request may wait for capacity before it is refused with 503 MODEL_UNAVAILABLE, for clients that would rather fail fast than wait. It can only shorten the server’s own wait, never lengthen it. Omit it to wait as long as the server allows.
Accepted WAV formats for both file and speaker: 16-, 24- or 32-bit integer PCM, or 32-bit float; mono or stereo (stereo is mixed down to mono); sample rates from 8 kHz to 48 kHz. Response 200: an audio/wav body, mono 16-bit PCM at 24 kHz, the same duration as the input. The X-Audio-Duration-Seconds header carries that duration.

Errors

Errors return the standard JSON error body, and every response carries an x-request-id header; see Error Codes.

Enhance live audio

Connect to wss://api.kugelaudio.com/v1/audio/enhance/stream and authenticate in the handshake, as for any WebSocket (Authentication). The API key, access to clarity-1, your plan (the free month, or your credits on paid) and its rate limits are all checked during the handshake, before the connection opens. A refusal is an HTTP response with the status and error_code from the table above, the standard error body and, where it applies, Retry-After; see Refused WebSocket upgrades.
  1. Client → text config:
    model is required and must be clarity-1. task is noise_removal or target_speaker_extraction. sample_rate_hz is 8000–48000. For target_speaker_extraction, add "speaker_wav_b64": the speaker sample as a base64-encoded WAV file, 2–8 seconds.
  2. Server → text {"type": "ready", "sample_rate_hz": 24000, "encoding": "pcm_s16le"}.
  3. Client → binary: mono 16-bit little-endian PCM at your declared rate, at most 1 second of audio per message.
  4. Server → binary: enhanced mono 16-bit little-endian PCM at 24 kHz, sent as it is produced.
  5. Client → text {"type": "end"}. The server sends the remaining audio, then {"type": "done", "duration_s": <seconds>}, and closes with 1000. The total output matches your input’s duration.

Several audios on one connection

Add session=1 to the URL to send one audio after another over the same connection, for example to open it while your agent starts and have it ready when the first user speaks: wss://api.kugelaudio.com/v1/audio/enhance/stream?session=1. Without session=1 the connection carries exactly one audio, as described above. The handshake checks the API key, access to clarity-1, your plan and (paid plan) that your credits cover at least one second, and counts the connection against your organization’s open-session limit. It does not use a request from your per-minute limit or a concurrent-request slot; each audio does. For each audio:
  1. Client → text the same config as above. This is when the audio counts against your per-minute and concurrency limits.
  2. Server → text {"type": "ready", "sample_rate_hz": 24000, "encoding": "pcm_s16le", "request_id": "<id>"}. request_id names this audio.
  3. Audio in and out, then {"type": "end"}, exactly as above.
  4. Server → text {"type": "done", "duration_s": <seconds>, "request_id": "<id>"}. The connection stays open for the next config, which may use a different task, speaker sample or sample rate.
Send {"type": "close"} (or close the WebSocket) between audios to end the session; the server closes with 1000. Each audio is billed on its own, for its input seconds (rounded up, one-second minimum), under its request_id. If a config is over your per-minute or concurrency limit, you get an error message with RATE_LIMITED (and retry_after for the per-minute limit) and the connection stays open; send the config again later. Every other error inside an audio closes the connection as described below. During a rolling deploy the server finishes the audio in progress, then closes with 1012; reconnect and continue.

Errors and close codes

After the connection opens, an error arrives as an error message in the standard error shape, with the connection’s request_id and, when a retry makes sense, retry_after in seconds:
The server then closes the connection with the close code for that error_code, the same codes text-to-speech uses; see WebSocket close codes. For this endpoint, 1000 is the normal close after done (for a session, after close, 60 idle seconds or one hour); 1012 means the server is restarting, so reconnect; 4000 means an invalid config or audio message, no audio for 30 seconds, or a stream longer than one hour of audio; 4003 means INSUFFICIENT_CREDITS or FREE_PERIOD_ENDED; and 1011 means enhancement failed mid-stream.

Warm up before audio

Enhancement capacity scales down when nobody uses it, so the first request after a quiet period can wait several seconds before it starts. If you know audio is coming (a user opened your recording screen, a call is about to connect), send this request first. It answers right away and readies enhancement in the background, so the request that follows starts without that wait. It needs the same API key and clarity-1 access as the other endpoints, takes no body, and is not billed. Response 202: {"status": "warming"}.
cURL
Errors are the 401, 402 FREE_PERIOD_ENDED and 403 rows of the recording endpoint’s error table.
Last modified on October 6, 2026