Speech-to-text · Alebex
Canada’s #1 streaming speech-to-text model. Alebex STT recorded a 3.96% word error rate for final transcription on September 21, 2026
Models / Speech-to-text

Transcribes fast. Understands the whole sentence. Knows when you’re done.

Streaming speech-to-text that keeps every word in context and predicts the end of the turn as the caller speaks, so the agent answers on time, not after a pause.

One free hour of audio on every new developer account. Sign up, take your token, start streaming.

Why it matters

Chunking is how streaming transcription got fast. It is also why it stumbles.

Cut speech into fixed pieces and every boundary is a place to lose a word, a name or a number. Alebex keeps the sentence whole and keeps the speed.

Same audio, two decoders 0.0 s
Caller 1.2 s chunks
Chunked decoders
Cut the audio into fixed pieces. Decode each on its own.
waiting for the first chunk to close…
Alebex
one WebSocket
One line, revised as context arrives.
Illustrative playback. Message fields as documented in the API.
Turn signal

Every transcript says whether the caller has finished.

“can i move it to friday” · partial
complete
0.88
incomplete
0.11
“can i move it to” · partial
complete
0.14
incomplete
0.83

Illustrative values. turn_state is null when no turn signal is available.

Trained on how a finished sentence sounds

To a silence timer, the pause after “and” and the pause after a finished sentence are the same silence. The model that writes the transcript also reads the turn: it hears the words and the intonation together, and was trained on how people sound when they have finished speaking. So “Can I move it to” stays open, and “Can I move it to Friday” closes.

Use it as advice with a score

Respond on COMPLETE above your own threshold, keep listening on INCOMPLETE, and fall back to your timer when the field is null.

The API

One WebSocket. Audio in, words out.

How the turn ends is your choice. Two shapes, and the only real difference is when you read a frame: the moment your own end-of-turn fires, or after you have asked for a final. Both come down the same socket in order, so the newest frame is always the one to render.

A

Snapshot, then reset

recommended for realtime

Hold one socket open. Each time your own end-of-turn fires, read the newest frame and reset for the next turn. You never wait for anything.

↓down↑up

 

Decides
Your side. Your own VAD, or turn_state COMPLETE on a partial you already have.
Text from
Whatever frame is newest when you decide. partial or final, you read it the same way.
Costs
Nothing extra. No round trip and no additional model pass, which is why this is the shape to reach for.
B

End, then final

one final per end

The speaker finishes, you send end, and the next frame down is a final. Guaranteed.

↓down↑up

 

Decides
Still your side, but you hand the call over: end means “flush what you have and answer”.
Text from
The final. Authoritative, with no snapshot bookkeeping of your own.
Costs
One extra model pass. end waits out the decode already running, then re-transcribes what is still buffered. That pass reads audio no partial has seen, which is also what you are buying.
Integration

Take a token, open the socket, send audio.

Your developer account issues the token. The client presents it when it opens the socket, and the same socket then carries the whole conversation. No key exchange and no second request.

1 · Take a token developer account · dashboard
Speech-to-text tokenactive
wt_1a2b3c4d5e6f•••••••••••• copy

The dashboard issues the token with the account. Copy it and hand it to the client: on the wire it travels as the WebSocket subprotocol alebex.token.<token>, so it never lands in a URL or an access log.

Developer accounts
2 · Stream from the browser client · JavaScript
const ws = new WebSocket(
  "wss://asr.alebex.ai/asr/ws",
  ["alebex.token.wt_1a2b3c4d5e6f..."]
);

ws.onopen = () => ws.send(JSON.stringify({ type: "start", language: null }));

// PCM 16-bit mono 16 kHz, as it is captured
recorder.ondata = (chunk) => ws.send(chunk);

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === "partial") draft(msg.text);
  if (msg.type === "final")   commit(msg.text, msg.turn_state);
};

ws.send(JSON.stringify({ type: "end" }));
Get access

Point a microphone at it today.

A developer account, a token from the dashboard, one WebSocket. You are streaming in minutes, and the first hour is on us.