Skip to main content
A page or an app that talks to the Streaming TTS API directly must not carry your API key: the key would be in the shipped code, in URLs, and in whatever logs those URLs reach. Mint a temporary token on your server instead, hand it to the client, and let the client open its session with that. The token is good for one short window, usage through it is attributed to the key that minted it, and a token cannot mint another token. Browsers cannot set headers on a WebSocket handshake, which is why the API also accepts the credential as a token query parameter. That parameter takes an API key too, but never send one from a device you do not control.
1

Mint a token on your server

GET https://token.assemblyai.com/v1/token with your API key in the Authorization header and two query parameters, both required: product=tts, and expires_in_seconds, how long the token can wait before it opens a session.
The Python SDK has no minting helper for Streaming TTS; the request above is all it takes.
The answer is JSON with the token in its token field, a long opaque string:
  • expires_in_seconds, 1 to 600, is the window in which the token can open a session. Past it the connection is refused with 1008 and Unauthorized: Signature has expired. A session that is already open is not affected when its token expires.
  • max_session_duration_seconds, optional and at least 60, caps the session opened with the token. The cap shows up as expires_at on the Begin frame, and the session closes with code 3008 when it is reached. A session never lasts longer than an hour either way.
  • Zones. token.us.assemblyai.com and token.eu.assemblyai.com serve the same route within the US and EU data zones, and a token from either opens sessions on both TTS hosts. Mint on the token host of the zone your sessions connect to, so that the minting request is processed in that zone too; see Cloud endpoints and data residency.
  • Errors. A key the route refuses, or a request it cannot accept, gets a 4xx answer with the reason in the JSON detail field. A 500 or 502 means the route could not issue a token just then: retry with backoff.
Mint a new token for every connection, reconnects included, and keep expires_in_seconds short. A token is not single-use: until it expires, it opens as many sessions and HTTP requests as it is given to, so a token that leaks from a page can be used by someone else. Never put your API key in the token parameter of a page you ship. The query string is part of the URL, and URLs are written to server access logs, browser history and developer tools.
2

Open the session with the token

The client fetches the token from your server, then passes it in place of the API key. In the fragments below, fetchToken() and fetch_token() are requests to your own server, and play() is whatever takes a chunk of audio in your app.
Give each connection a token of its own: to reconnect, mint a new token and build a new session with it. The session opens on the US host unless aai.settings.tts_base_url names the EU one; see Cloud endpoints and data residency.
A token that was refused, because it expired or was minted for another product, closes the session with 1008 and error_type unauthorized before Begin. See Error handling.

Where else a token works

A temporary token works wherever an API key does, in the Authorization header of the HTTP API, so a page can call it directly too. Under a token, max_session_duration_seconds also caps how long an HTTP request may run. See HTTP API basics.

Speak a whole text over HTTP from a page

A page with a whole text to speak and no need for barge-in can call the HTTP API directly, one fetch per text, played as it streams in. Every route answers cross-origin requests from any origin. Send the token in the Authorization header like a key; the HTTP API reads the credential from that header only. A token stays valid for any number of requests until it expires, so the page can retry a failed request with the same token. The client below schedules each piece of audio on one AudioContext as it arrives, so playback starts with the first bytes. Create and resume the context in a user gesture, and reuse it for every request. /tts-token is a route on your server that returns a freshly minted token as JSON.
Every response header can be read from a page, errors included, so X-Request-Id and the X-TTS-* headers are available to your error reporting.