Authentication
How to send your API key, what a key may do, and how to tell a rejected key from one without permission.
Sending the key #
Send the key as a bearer token in the Authorization header. A missing or wrong key is 401. Browsers send it differently; see Browser credentials.
Authorization: Bearer <token>Key format #
Keys have the form srk_<16>_<32>: a 16-character key id and a 32-character secret, both from the alphabet abcdefghijklmnopqrstuvwxyz234567.
srk_aaaaaaaaaaaaaaaa_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaA key is shown exactly once, when it is issued, and is never recoverable, because the service keeps only a salted SHA-256 verifier. If you lose a key, issue a new one and revoke the old.
Scopes #
Scopes limit what a key may do. An empty scope set means unrestricted. The asr scope covers creating sessions, streaming and transcribing; admin covers the operator routes. These scopes narrow which sessions a key may create:
mode_mt,mode_ts— only the modes named.speakers_1up to the engine's limit,speakers_8on HEAT4 andspeakers_4ondicon—expected_num_speakersat most the smallest number the key carries;"auto"counts as the whole limit, eight speakers on HEAT4 and four ondicon. A scope above the engine's limit is refused, never ignored.store_content— required to sendstore_content: true, even by a key with no other scopes.
They apply to POST /v1/sessions, WS /v1/stream and POST /v1/transcriptions. A refusal is 403 over HTTP. On WS /v1/stream it is an error event with code: "forbidden" followed by close 4400, because the mode and speaker count arrive in the first message, after the connection opens.
401 versus 403 #
401 we do not accept this credential missing, wrong or expired
403 we accept it but it may not do this valid, but outside its scopesExpiry and revocation #
A key may carry an expiry, checked on every request; once it passes, the key is 401. Revocation is not instant: a revoked key stops working once the service's verification cache and storage catch up, not at the moment you revoke it.
Browser credentials #
A browser cannot set an Authorization header on a WebSocket, so /v1/stream also accepts the key in the Sec-WebSocket-Protocol header, as bearer.<token> next to dicon.v1:
const socket = new WebSocket(url, ["dicon.v1", `bearer.${token}`]);If both forms are present, the Authorization header wins. The server selects dicon.v1 and never echoes the credential back. This keeps the key out of URLs and access logs, but a proxy that logs full request headers will still capture it.
A rejected key on a WebSocket upgrade gets a real HTTP response, 401, and the connection never opens.