Skip to main content
HyperWhisper contains an HTTP server. You can turn on this server from Settings → API Server on macOS, or Settings → Local API on Windows. The server listens on 127.0.0.1 only. It never listens on the LAN. The server writes the bound port and a bearer token to a discovery file on disk. MCP wrappers, benchmark scripts, and shell automation read this file to find the server, and they need no configuration.

Discovery file

The file has chmod 600 permissions on macOS. It has this JSON shape:

Authentication

Every endpoint except /health needs this header:
The server makes the token at the first start (32 random bytes, base64-url-encoded). On macOS, the server keeps the token in the Keychain. On Windows, it keeps the token in a DPAPI-protected blob at %LOCALAPPDATA%\HyperWhisper\local-api-token.bin. You can make a new token from Settings → API Server (macOS) or Settings → Local API (Windows). The previous token then becomes invalid immediately.

Response envelope

The server returns both shapes with HTTP 200:
The server uses HTTP 4xx for protocol failures only:
  • 400 for malformed JSON
  • 401 for a missing or invalid bearer token
  • 403 for a rejected Host/Origin header. This is a DNS-rebinding guard on every route, including /health.
All other errors arrive as ok:false with a machine-readable code, and with HTTP 200. Examples are a transcription engine error, a missing API key, and a file that the server cannot find. Read the code, not the status.

Request limits

The server refuses a request that is too large: A refusal is a business failure, not a protocol failure. The server returns HTTP 200 with this envelope:
The message is Audio exceeds the configured upload limit. when the audio limit is the one that the request passed. audio_base64 stops at 37.5 MiB, not at 48 MiB. Base64 turns 3 bytes of audio into 4 characters, and the request limit applies to those characters. So the request limit is always the first one that a large audio_base64 payload passes: it stops the audio at 39,321,600 bytes (37.5 MiB), and a little below that, because the JSON around the string counts too. Design against 37.5 MiB when you put audio in the JSON body. A payload above it gets Request exceeds the configured limit., never the audio message. To send more audio than that, keep it out of the JSON body: use a file path, or a multipart audio part on Linux. Neither travels as base64, so the audio limit of 48 MiB is the one that can apply to them. The list below gives the limit that each platform applies to each one. Each platform applies the limits differently:
  • macOS applies the request limit to every route that reads a body, and always answers with the HTTP 200 envelope. It applies the audio limit to audio_base64 and to a file path. For audio_base64 the limit is out of reach, because the request limit refuses the payload first; for a file path it is reachable, and a file above 48 MiB gets Audio exceeds the configured upload limit. macOS accepts no multipart request. So a file path is how you transcribe audio between 37.5 MiB and 48 MiB on macOS.
  • Linux applies both limits, and both are reachable. It applies the audio limit to a multipart audio part and to a file path as well as to audio_base64. A file path above 48 MiB gets the same refusal here as on macOS. Only /transcribe answers with the HTTP 200 envelope. On the other routes, the web server stops the body itself and returns a bare 413 with no envelope.
  • Windows applies both limits, and both are reachable. The request limit applies to every route that reads a body — POST /transcribe, POST /post-process, POST /modes and PATCH /modes/{id} — and each one answers with the HTTP 200 envelope. The audio limit applies to the decoded bytes of audio_base64 and to a file path, so a file path above 48 MiB is refused here and on Linux but accepted on macOS. Windows accepts no multipart request. Older Windows builds used neither value. Their web server kept its own default of 30,000,000 bytes (approximately 28.6 MiB), the refusal arrived as HTTP 400 with the message Invalid JSON body — which a client could not tell from malformed JSON — and there was no audio limit at all. Read the code and the message, and keep your client tolerant of both answers if it must support older builds.
Do not use 413 to find an oversized request. PAYLOAD_TOO_LARGE is not one of the codes in the closed set, and a client that shares the macOS decoder cannot read an envelope that contains it. Read the code, not the status.

Endpoints

The full schema is in openapi.yaml.

Next: MCP

An agent can call HyperWhisper as a tool in Cursor, Claude Desktop, or Claude Code. To set up this connection, read the MCP setup guide.