Docs / Realtime API / Client secrets

Realtime API

Client secrets

A browser should never hold your API key. Create a client secret on your server: it carries the session’s configuration and opens one session.

Create a client secret

POST
https://api.dotwave.ai/v1/realtime/client_secretsAuthenticate with your API key. This is the path the OpenAI SDK calls.
curl https://api.dotwave.ai/v1/realtime/client_secrets \
  -H "Authorization: Bearer $DOTWAVE_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "expires_after": {"anchor": "created_at", "seconds": 60},
    "session": {
      "type": "transcription",
      "audio": {
        "input": {
          "format": {"type": "audio/pcm", "rate": 24000},
          "transcription": {
            "model": "nemotron-asr-streaming",
            "language": "pt-BR"
          }
        }
      }
    }
  }'
expires_after.seconds
How long the secret stays valid: 60 by default, 600 at most.
session.type
transcription.
session.audio.input
The format, the model and language under transcription, and turn_detection, as in session.update. See client events.
turn_detection.idle_timeout_ms
How long the session stays open without audio: 30000 by default, from 10000 to 300000.

The response

Fields without effect come back as null. session.live_url is the socket to open.

{"value": "…", "expires_at": 1790000000,
 "session": {"id": "sess_…", "object": "realtime.transcription_session",
             "type": "transcription", "model": "nemotron-asr-streaming",
             "audio": {"input": {"format": {"type": "audio/pcm", "rate": 24000},
                                 "transcription": {"model": "nemotron-asr-streaming",
                                                   "language": "pt-BR", "prompt": null},
                                 "noise_reduction": null,
                                 "turn_detection": {"type": "server_vad", "threshold": null,
                                                    "prefix_padding_ms": null,
                                                    "silence_duration_ms": 3200,
                                                    "idle_timeout_ms": 30000}}},
             "live_url": "wss://api.dotwave.ai/v1/realtime"}}

Connect from a browser

Browsers cannot set headers on a WebSocket, so pass the secret as the token query parameter:

// `secret` is the `value` your server received. The session is
// already configured, so the browser only sends audio.
const ws = new WebSocket(
  `wss://api.dotwave.ai/v1/realtime?token=${encodeURIComponent(secret)}`,
);

ws.onmessage = ({ data }) => {
  const event = JSON.parse(data);
  if (event.type === 'conversation.item.input_audio_transcription.delta') {
    captions.textContent += event.delta;
  }
};

// 24 kHz mono PCM16 from an AudioWorklet, base64-encoded.
function sendAudio(base64: string) {
  ws.send(JSON.stringify({ type: 'input_audio_buffer.append', audio: base64 }));
}

A secret opens one session and expires at expires_at. An unused secret counts toward your concurrency limit until it expires. A secret from this endpoint can open the Deepgram-compatible socket instead.