Skip to main content
An API key in browser code can be read by anyone who opens the page, and spends your balance. Instead, keep the key on your server and give the page a ticket: a credential that starts with wst_, works anywhere a key does, and expires after 10 minutes (Authentication).

1. Backend: mint tickets

Put this route behind your own login, so only your signed-in users can get a ticket. Example with Node.js 22+ and Express:
The key goes in the Authorization (or X-API-Key) header. POST /ws-ticket does not accept it in the URL.

2. Browser: pass the ticket with auth

VoiceAgentClient takes an auth callback instead of apiKey. The SDK calls it before every connection, including each automatic reconnect, so a session that reconnects after the first ticket expired still gets a valid one.
TTSClient, STTClient and SpeechToTextClient take a credential as apiKey. Pass a ticket there, fetched just before use:
A ticket can be reused until it expires, so one ticket can serve several requests made within its 10 minutes.

Without the SDK

Pass the ticket as ?api_key=, since the browser WebSocket and EventSource cannot set headers:

Checklist

  • No sk_ key in any file the browser downloads, including .env values your bundler inlines (for example VITE_* or NEXT_PUBLIC_* variables).
  • The ticket route requires your own authentication; otherwise anyone can mint tickets on your balance.
  • Rate-limit the ticket route per user if your app is public.