Real-time Transcription (Speech-to-Text)
Stream audio and receive low-latency Speech-to-Text results over WebSocket. This endpoint is the recommended starting point for live transcription and automatically detects the spoken language.
Recommended endpoint
wss://api.valsea.ai/v1/realtime/asr
Connect here first. Omit language or set it to auto for automatic
detection.
Automatic language detection is the default
One unified API for every language and accent. Stream audio to a single endpoint and VALSEA automatically detects the spoken language—no language selection required.
valsea-rtt automatically detects the spoken language by default, so you do not need to select an
input language in advance — language can be omitted from the session.start message entirely.
You can make this explicit by setting language to "auto".
{
"type": "session.start",
"model": "valsea-rtt"
}
VALSEA supports 181 languages, dialects, and variants overall; coverage varies by endpoint. Auto-detect supports multilingual conversations and code-switching, including language changes within a conversation or sentence. If you already know the input language, you can pin it with a specific language code — see Use a fixed input language at the bottom of this page.
Connection
Endpoint: wss://api.valsea.ai/v1/realtime/asr
Authentication
You must authenticate the WebSocket connection by passing your API key in the HTTP headers during the handshake.
Headers:
Authorization:Bearer YOUR_API_KEY(Recommended)X-API-Key:YOUR_API_KEY(Supported)
Browser clients can also authenticate with ?api_key=YOUR_API_KEY because standard browser
WebSocket constructors do not support custom headers.
Paid Rate-Limit Bypass
If you need to exceed the realtime connection RPM limit for a session, you can bypass the rate-limit check by sending one of these opt-in flags during the WebSocket handshake:
- Header:
X-Bypass-Rate-Limit: true - Query parameter:
bypass_rate_limit=true - Query parameter:
bypassRateLimit=true
Bypass applies only to the per-organization rate-limit check. Authentication, credit checks, and
session billing still apply. RTT sessions using this bypass are billed at 2x the normal realtime
credit cost. The initial session.created event includes rateLimitBypass: true and
billingMultiplier: 2 when bypass is active.
Message Flow
- Connect: Client establishes WebSocket connection.
- Session Created: Server sends
session.createdevent. - Start Session: Client sends
session.startto configure language and model. - Stream Audio: Client sends
audio.appendmessages with base64-encoded PCM16 audio chunks. - Receive Transcripts: Server streams
transcript.partialandtranscript.finalevents. - Commit Audio: Client sends
audio.commitwhen a user stops speaking (optional/VAD dependent). - Stop Session: Client sends
session.stopto end the session.
Partial vs Final (Important)
RTT emits two transcript event types for each utterance:
transcript.partial: low-latency, in-progress text. This can change as more audio arrives.transcript.final: stable text for a completed segment. Treat this as the committed result.
Recommended client behavior:
- Keep a temporary
currentPartialstring fortranscript.partial. - Append only
transcript.finalto your persisted transcript history. - Clear
currentPartialwhen you receive a matchingtranscript.final.
Do not persist partial text as final output. Partials are intentionally mutable and may be revised by the engine before a final segment is produced.
Client Messages
session.start
Initialize the session with configuration.
{
"type": "session.start",
"model": "valsea-rtt",
"hint_text": "Optional context or vocabulary",
"enable_correction": true,
"language": "auto",
"language_hints": ["en", "vi", "ar"],
"noise_suppression": "off"
}
This endpoint never translates. If you send target_language, it is silently ignored — no
validation runs against it, so an unsupported or malformed value here will not end your
session (unlike /v1/realtime/translate and /v1/realtime/notetaker, where the same input would
return INVALID_TRANSLATION_TARGET and close the connection). Speaker diarization (diarize) is
also always disabled on this endpoint, regardless of what you send.
Timestamp limitation (English): When diarize=true for English, word and utterance start /
end timestamps will always be 0. Speaker labels and transcript text are still correct.
audio.append
Send audio data.
{
"type": "audio.append",
"audio": "BASE64_ENCODED_PCM16_DATA"
}
- Format: Raw PCM 16-bit, 16kHz (recommended), mono.
- Encoding: Base64 string.
You may also send raw binary PCM16 frames directly over the WebSocket. Binary frames are treated as
audio.append messages by the server.
audio.commit
Signal the end of a speech segment (e.g., VAD triggered silence).
{
"type": "audio.commit"
}
session.stop
End the session gracefully.
{
"type": "session.stop"
}
Server Messages
session.created
Sent immediately upon connection.
{
"type": "session.created",
"sessionId": "rtt_...",
"supportedModels": ["valsea-rtt"]
}
session.ready
Sent when the backend engine is connected and ready to receive audio.
{
"type": "session.ready",
"sessionId": "rtt_...",
"engine": "valsea-7"
}
engine is an opaque identifier for the backend that handled your session.transcript.partial
Intermediate transcription results (low latency, may change).
{
"type": "transcript.partial",
"text": "The quick brown",
"isFinal": false,
"timestampMs": 1888
}
transcript.final
Finalized text for a speech segment. On this endpoint, text and rawText are always identical —
translation fields (translated, sourceLanguage, targetLanguage) never appear here.
{
"type": "transcript.final",
"text": "The quick brown fox jumps over the lazy dog while the market opens at 9.30 in the morning.",
"rawText": "The quick brown fox jumps over the lazy dog while the market opens at 9.30 in the morning.",
"isFinal": true,
"timestampMs": 6328
}
error
Sent when an error occurs.
{
"type": "error",
"code": "INVALID_MESSAGE",
"message": "Failed to parse message"
}
Error codes on this endpoint
Event Handling Pattern
Use this pattern to avoid duplicated or unstable transcript content:
let currentPartial = '';
const finalSegments = [];
ws.on('message', (raw) => {
const msg = JSON.parse(raw);
if (msg.type === 'transcript.partial') {
currentPartial = msg.text || '';
}
if (msg.type === 'transcript.final') {
finalSegments.push(msg.text || '');
currentPartial = '';
}
});
Example (Node.js)
const WebSocket = require('ws');
const fs = require('fs');
const ws = new WebSocket('wss://api.valsea.ai/v1/realtime/asr', {
headers: { 'X-API-Key': 'YOUR_KEY' },
});
ws.on('open', () => {
ws.send(
JSON.stringify({
type: 'session.start',
model: 'valsea-rtt',
}),
);
});
ws.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.type === 'session.ready') {
const audioStream = fs.createReadStream('audio.raw');
audioStream.on('data', (chunk) => {
ws.send(
JSON.stringify({
type: 'audio.append',
audio: chunk.toString('base64'),
}),
);
});
} else if (msg.type === 'transcript.final') {
console.log('Final:', msg.text);
}
});
Use a fixed input language
By default, sessions auto-detect the input language. If you already know the language being spoken, set it explicitly for the most consistent routing:
{
"model": "valsea-rtt",
"language": "singlish"
}
Language Hints
Automatic detection is recommended. Omit language or send "language": "auto" in session.start. If you know the input language, you may send a supported code such as english, singlish, vietnamese, arabic, arabic-egypt, or arabic-uae to constrain routing.
Bias Automatic Detection
When using automatic detection, optionally send language_hints with up to 20 expected two- or three-letter language codes. For example, ["en", "vi", "ar"] biases detection toward English, Vietnamese, and Arabic while still allowing other languages to be detected. Values are normalized to lowercase and deduplicated; invalid entries are ignored. The field has no effect when language is fixed.
VALSEA supports 181 languages, dialects, and variants overall. Availability and feature coverage vary by endpoint. See the current supported-language matrix for the authoritative list.