Skip to main content
If your app calls Dictation from your users’ devices (a desktop app, a mobile app or a web page), don’t ship your API key in it. Anyone can read a key out of an app or its network traffic and use it for anything your account can do. Instead, your server keeps the key and hands each signed-in user a temporary token when they’re about to dictate. The token works in place of your key, only for Dictation, and expires after a short window. If you send your own rewrite prompt, save it in your account so the app sends its name instead of the prompt.
1

Your server mints a token

When a signed-in user is about to dictate, your server sends your API key to the token endpoint and gets back a token that can only open Dictation.
2

Your app dictates with the token

The app sends the dictation request as usual, with the token in the Authorization header instead of your API key.
3

The token expires

The token stops opening new requests after the time you set, so a token that leaks is worth little.

Mint a Dictation-only token

Send POST to a token host with your API key and an access block that turns off every other product:
"product": "dictation" on its own doesn’t stop the token opening other products. Without the access block, a token minted for Dictation can also call Streaming, Sync, the Voice Agent API, TTS and LLM Gateway, billed to your account. Always send the access block from a token you hand to a user’s device.
Turning off sync and llm_gateway doesn’t affect Dictation, which calls them with its own credentials, not your token. llm_response, llm_instruction, rewrite_mode and saved prompts work the same with a Dictation-only token. Here’s the same request from a server, in Python and Node.js:
Serve this from an endpoint in your own backend that only your signed-in users can call. See Temporary tokens for every field the token endpoint takes.

Dictate with the token

On the device, send the dictation request exactly as you would with your API key, and put the token in the Authorization header. Both endpoints accept the token, and both allow requests from any web origin, so a browser can call Dictation directly:
To upload while the user is still speaking, use the same token with the streaming request in Achieve lowest latency.

Keep tokens off the critical path

Fetching a token is one more round trip, so don’t wait to fetch it until the user starts speaking:
  • Fetch it early. Mint a token when the user is likely to dictate soon, such as when your dictation UI opens or the app comes to the front, and keep it until it’s close to expiring.
  • Mint a fresh token before it expires. expires_in_seconds is how long a token can wait before it opens a request, from 1 to 600. A request that opens in time runs to the end, even a long recording on /v1/transcribe.
  • Keep the window short. Until it expires, a token can open more than one request. A short window limits what a leaked token can do.
  • Pre-warm without a token. GET /warm needs no key or token, so you can warm the connection while the token is still on its way.
Mint the token before you start recording. If a streaming request is rejected with 401 partway through, the audio you already streamed can’t be sent again, so get a fresh token first and avoid starting a dictation on a token that’s about to expire.

Protect your mint endpoint

Usage through a token is billed to the API key that minted it, and a token carries nothing about which of your users it was minted for. Your backend is the only place that knows who asked for each token, so put your controls there:
  • Mint tokens only for users who are signed in to your app.
  • Rate-limit the endpoint per user, for example a few tokens a minute, which is plenty for dictation.
  • Log which user each token was minted for, so you can trace unusual usage back to an account and block it.

Keep your prompt off the device

If you rewrite with your own prompt, the prompt travels in every request your app sends, where anyone inspecting the traffic can read it. Save the prompt in your account instead, and have the app send only its name. Create the saved prompt once, from your server or as a deploy step, with your API key. Put {{ text }} where the transcript goes:
Then the app refers to it by name in the llm field of its dictation config, with any per-user values in prompt_replacements:
The prompt itself never reaches the device, and you can change it without shipping a new version of your app. The model, max_tokens and other settings come from the saved prompt, so don’t send rewrite_mode or other llm fields with it. See Sending your own LLM request for the details.

Data zones

Mint the token on the token host for the data zone your app sends dictations to: See Cloud endpoints & data residency.