Skip to main content
Stream raw PCM audio over a WebSocket and receive the same audio back with background noise removed. The service runs AI noise suppression on Telnyx infrastructure. It is independent of calls: use it for any audio source, for example before you send audio to a speech-to-text engine.
To remove noise from a live Voice API or TeXML call, use in-call noise suppression instead. This page covers the standalone WebSocket API.

Endpoint

Authentication

Send your API key in the Authorization header of the WebSocket upgrade request:
A request without valid credentials fails with HTTP 401 before the WebSocket opens.

Connection lifecycle

1. Handshake

Set all options as query parameters on the upgrade request. You cannot change them during the session.

2. Streaming

Send audio as binary frames. For each binary frame you send, the server returns exactly one message:
  • a binary frame with denoised audio, or
  • a text frame with a JSON error (see Errors).

3. End of stream

When you have no more audio, send this text frame:
The server then returns all remaining audio, including the audio held back by the model’s processing delay, as one final binary frame. Then it closes the connection with close code 1000. Keep reading until you receive the close frame.
Always send end_of_stream before you stop. If you close the WebSocket without it, the server cannot send the remaining audio, and the end of your stream is lost.

Query parameters

An unsupported value closes the connection with an invalid_params error and close code 1008. See Errors.

Sample rates

The service accepts any integer sample rate from 8000 to 48000 Hz. A value outside that range closes the connection with an invalid_params error and close code 1008. The output uses the same sample rate as the input. Use the native sample rate of your audio. Send telephony and PSTN (narrowband) audio at 8000. Do not upsample 8 kHz audio to a higher rate. The full-band model treats the missing upper band as noise and lowers the speech level by about 14 dB.

Models

You select the model family with model. The service selects the model variant that matches your sample_rate. Above 16000, quail processes the audio with the 16 kHz model. The output keeps your sample rate, but its audio bandwidth is limited to the 16 kHz model’s bandwidth (8 kHz).

Quality

quality sets the enhancement strength: how much noise the model removes. Any other value, for example 1.5 or max, closes the connection with an invalid_params error.

Audio format

Audio is raw mono PCM with no container and no header. Do not send WAV headers. Strip the header and send only the sample data. The output uses the same format and sample_rate as the input.
l16 is little-endian. This is different from the big-endian L16 of RTP (RFC 3551). Byte-swap RTP payloads before you send them.

Chunk size

  • Each binary frame must contain a whole number of samples: a multiple of 2 bytes for l16, a multiple of 4 bytes for f32le.
  • The maximum binary frame size is 65,536 bytes.
  • 20 ms chunks are a good default. At 16 kHz l16, 20 ms is 640 bytes. At 8 kHz l16, 20 ms is 320 bytes.

Buffering and latency

The model processes audio in fixed-size internal frames, and it has a short processing delay. The server keeps input that does not fill a complete frame and processes it together with your next chunk. As a result:
  • A response can be smaller or larger than the matching request. It can also be an empty binary frame. Ignore empty frames.
  • The output starts with the model’s processing delay. The first samples you receive correspond to that delay, not to your first input samples.
  • When you send end_of_stream, the server returns all of the audio that it still holds. The total output is your input length plus the processing delay.

Session duration

Sessions are limited to 590 seconds (just under 10 minutes). Reconnect to continue longer streams. At the limit, the server returns the remaining audio, sends a max_session_duration error message, and closes the connection with code 1008. You do not lose audio. To end with a normal close (1000) instead, send end_of_stream before the limit and then open a new connection for the rest of the stream.

Errors

HTTP errors (handshake)

Error messages

The server sends errors as JSON text frames:
code is a stable identifier. message is a human-readable description; do not parse it.

Error codes

Close codes

When the server closes the connection, the close frame reason is the error code. Before every close that the server makes with a code other than 1000, including at the session limit, it sends the matching error message. A close caused by a network failure comes without an error message.

Reconnecting

Close code 1001 and HTTP 503 mean that the server is restarting, for example during a deploy. Close codes 1011 (server error) and 1013 (service busy) are also temporary. None of these are errors in your request. Reconnect with exponential backoff; the new session goes to a healthy server. The new session starts empty: the service keeps no state between connections. Audio that you sent after the server started to close is not returned. For a live stream, continue with new audio on the new connection. For a file, send the file again.

Next steps

See Examples for complete Python and Node.js code that denoises a WAV file.