> ## Documentation Index
> Fetch the complete documentation index at: https://hyperwhisper.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Start the microphone, or stop it and transcribe

> Linux only. macOS and Windows do not serve this path. The route takes no
request body and no `mode_id`, so it uses the current Mode.

When the recorder is idle, the call starts it. When the recorder is
recording, the call stops it and transcribes, and it waits for that
transcription — so it is as slow as a `/transcribe` call.

A call during the `stopping` or the `transcribing` state is refused with
HTTP 400 and the code `INVALID_REQUEST`, because a transcription is
already in progress.




## OpenAPI

````yaml /api-reference/local-api/openapi.yaml post /recording/toggle
openapi: 3.0.3
info:
  title: HyperWhisper Local API
  description: >
    HTTP API exposed by HyperWhisper.app on `127.0.0.1` when the user enables

    Settings → API Server. Off by default. Used by MCP wrappers, benchmarking

    scripts, and power-user automation.


    **Port + token discovery.** The server writes

    `~/Library/Application Support/HyperWhisper/local-api.json`

    (chmod 600) on every start. Clients read that file to find the port

    and bearer token — neither value is hard-coded.


    **Response envelope.** Successful calls return `{"ok": true, ...}` with

    HTTP 200. Expected business failures (model not installed, missing API

    key, file not found, transcription engine errored, etc.) also return HTTP

    200 with `{"ok": false, "error": {"code": "...", "message": "...", "hint":
    "..."}}`.

    HTTP 4xx is reserved for protocol failures: malformed JSON (400), missing

    or invalid bearer token (401), or a rejected Host/Origin header (403 — a

    DNS-rebinding guard applied to every route, including the unauthenticated

    /health, on every platform). On macOS, a request head over 8 KiB a line

    or 64 KiB in total gets a bare 431 and the connection closes.
  version: 1.0.0
servers:
  - url: http://127.0.0.1:{port}
    description: >-
      Local-only loopback. The port is dynamic — read it from the discovery
      file.
    variables:
      port:
        default: '39201'
        description: >-
          Persisted port from `~/Library/Application
          Support/HyperWhisper/local-api.json`.
security:
  - bearerAuth: []
paths:
  /recording/toggle:
    post:
      summary: Start the microphone, or stop it and transcribe
      description: |
        Linux only. macOS and Windows do not serve this path. The route takes no
        request body and no `mode_id`, so it uses the current Mode.

        When the recorder is idle, the call starts it. When the recorder is
        recording, the call stops it and transcribes, and it waits for that
        transcription — so it is as slow as a `/transcribe` call.

        A call during the `stopping` or the `transcribing` state is refused with
        HTTP 400 and the code `INVALID_REQUEST`, because a transcription is
        already in progress.
      responses:
        '200':
          description: Recorder state after the toggle
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RecordingStateResponse'
        '400':
          description: A transcription is already in progress
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
components:
  schemas:
    RecordingStateResponse:
      type: object
      properties:
        ok:
          type: boolean
        recording:
          $ref: '#/components/schemas/RecordingState'
    ErrorEnvelope:
      type: object
      required:
        - ok
        - error
      properties:
        ok:
          type: boolean
          enum:
            - false
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - MODEL_NOT_INSTALLED
                - MODEL_NOT_FOUND
                - ENGINE_UNAVAILABLE
                - MISSING_API_KEY
                - FILE_NOT_FOUND
                - FILE_ACCESS_DENIED
                - FILE_NOT_ALLOWED
                - AUDIO_DECODE_FAILED
                - TRANSCRIPTION_FAILED
                - MODE_NOT_FOUND
                - MODE_NAME_TAKEN
                - INVALID_REQUEST
                - RATE_LIMITED
                - TIMEOUT
            message:
              type: string
            hint:
              type: string
    RecordingState:
      type: object
      description: State of the live recorder. Linux only.
      properties:
        is_recording:
          type: boolean
          description: True for the `recording` state only.
        state:
          type: string
          enum:
            - idle
            - recording
            - stopping
            - transcribing
            - retrying
            - completed
            - cancelled
            - failed
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: base64-url
      description: >-
        Token from the discovery file. Required on every endpoint except
        /health.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.