Authentication
Create an access token
Mint a short-lived, single-use token so a browser can synthesize without your API key.
POST
Create an access token
Exchanges your API key for a short-lived, single-use access token (
fin_tok_…). Your server calls
this endpoint, hands the token to the browser, and the browser uses it to open the
Realtime WebSocket or call speak /
stream directly. The API key itself never leaves your server.
- Short-lived - expires after
ttl_seconds(default 300, max 3600). - Single use - consumed on its first successful use: one WebSocket handshake, or one
speak/streamrequest. A request refused before it runs (a429rate limit, a plan check) keeps the token, so you can retry with it. Mint a new token for each session or request. - Text-to-speech only - a token grants the
ttsscope and nothing else. It can’t list, create or clone voices. - Optionally voice-restricted - pass
voice_idsto limit which voices the token can synthesize with. - Tied to its key - it uses the creating key’s workspace and stops working if that key is revoked or expires.
Authorization
string
required
Your workspace API key (
flv_…). Required scope: tts.Body
All fields are optional; an empty body (or{}) mints a 5-minute token for any voice.
integer
default:300
Token lifetime in seconds,
10–3600. Out of range returns 400.string[]
Restrict the token to these voices. Each id must be a voice your key’s workspace can use, otherwise
the request returns
400 naming the bad id. Omit to allow any voice in the workspace. Using the
token with another voice returns voice_not_allowed.Response
string
The access token (
fin_tok_…). Shown only in this response - the server stores a hash.integer
When the token expires, as Unix epoch milliseconds.
integer
The effective lifetime in seconds.
Response
Browser flow
1
Your server mints a token
When a signed-in user needs audio, your backend calls
POST /tokens with your API key (scope tts),
optionally restricting voice_ids to what that user may use.2
Hand the token to the browser
Return only the
token (and expires_at) to your frontend. Never send the API key.3
The browser uses it once
Open the WebSocket with the token as a subprotocol, or call
speak / stream with
Authorization: Bearer <token>. The token is consumed on that first successful use.If your WebSocket client can’t send subprotocols, pass the token as
?access_token=fin_tok_… on the
stream URL instead. The older ?api_key= query parameter still works but is deprecated - it puts
your long-lived key in URLs and browser history.Errors
When the browser uses the token: an unknown, expired or already-used token returns
401
token_invalid (on the WebSocket, the handshake fails with 401); a voice outside voice_ids returns
403 voice_not_allowed on HTTP, or a non-fatal voice_not_allowed error frame on the WebSocket. See
Errors.

