HTTP API and CLI automation
TypeWhisper includes a versioned local HTTP API for scripts and external tools. The documented /v1/* surface covers transcription, app data, settings backups, dictation, Recorder, and workflow-driven automation.
Local only: The server is disabled by default and binds only to 127.0.0.1. Do not proxy or expose it to a public network.
Setup and authentication
Enable API Server in Settings > Advanced. The default port is 8978; TypeWhisper writes the active port and a generated token to ~/Library/Application Support/TypeWhisper/api-discovery.json while the server is running.
Require API Token is off by default for compatibility with existing local integrations. When enabled, send the discovery token as a Bearer token on every endpoint except GET /v1/status.
DISCOVERY="$HOME/Library/Application Support/TypeWhisper/api-discovery.json" export TYPEWHISPER_API_PORT="$(jq -r '.port' "$DISCOVERY")" export TYPEWHISPER_API_TOKEN="$(jq -r '.token' "$DISCOVERY")" curl "http://127.0.0.1:$TYPEWHISPER_API_PORT/v1/models" \ -H "Authorization: Bearer $TYPEWHISPER_API_TOKEN"
GET /v1/status remains public for readiness checks. Clients may alternatively send the same token in the X-TypeWhisper-API-Token header.
The discovery file is created with owner-only permissions (0600) and removed when the server stops. The TypeWhisper CLI discovers both its port and token automatically; --port, --api-token, and TYPEWHISPER_API_TOKEN provide explicit overrides.
Endpoint reference
The table below reflects all 26 routes registered by the current macOS implementation, including the two legacy /v1/profiles aliases and the settings backup routes.
Status, models, and transcription
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /v1/status | Report readiness, selected engine/model, API version, and capability flags. |
| GET | /v1/models | List every model exposed by loaded transcription engines and its current state. |
| POST | /v1/transcribe | Transcribe multipart or raw audio, with optional language, engine, model, translation, prompt, and correction controls. |
| POST | /v1/transcribe/local-file | Transcribe an absolute file path already accessible to the running Mac app; used by the CLI to avoid uploading local files. |
History, Dictionary, and settings
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /v1/history | Search and paginate transcription history. |
| DELETE | /v1/history?id=<uuid> | Delete one history entry by UUID. |
| GET | /v1/dictionary/terms | List enabled recognition terms and optional CTC similarity thresholds. |
| PUT | /v1/dictionary/terms | Merge or replace recognition terms. |
| DELETE | /v1/dictionary/terms | Delete one recognition term. |
| GET | /v1/dictionary/corrections | List post-transcription Dictionary Corrections. |
| PUT | /v1/dictionary/corrections | Add or update one Dictionary Correction. |
| DELETE | /v1/dictionary/corrections | Delete one Dictionary Correction by its original text. |
| GET | /v1/settings/export | Export the complete Settings Backup JSON document. |
| POST | /v1/settings/import | Import a Settings Backup document and return a machine-readable merge/skip summary. |
Workflows, dictation, and Recorder
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /v1/rules | List workflow-backed automation rules. |
| PUT | /v1/rules/toggle?id=<uuid> | Toggle one workflow-backed rule by UUID. |
| GET | /v1/profiles | Legacy alias for GET /v1/rules. |
| PUT | /v1/profiles/toggle?id=<uuid> | Legacy alias for PUT /v1/rules/toggle. |
| POST | /v1/dictation/start | Start system-wide dictation, optionally forcing an enabled workflow. |
| POST | /v1/dictation/stop | Stop the active API dictation session. |
| GET | /v1/dictation/status | Report the live dictation state, model, and active workflow. |
| GET | /v1/dictation/transcription?id=<uuid> | Poll a dictation session for completion, transcription, or failure. |
| POST | /v1/recorder/start | Start Recorder with optional microphone and system-audio overrides. |
| POST | /v1/recorder/stop | Stop and begin finalizing the active API Recorder session. |
| GET | /v1/recorder/status | Report whether Recorder is currently recording. |
| GET | /v1/recorder/session?id=<uuid> | Poll a Recorder session for status, text, output file, or failure. |
Check status
curl http://localhost:8978/v1/status
{
"status": "ready",
"engine": "whisper",
"model": "openai_whisper-large-v3_turbo",
"api_version": "1.1",
"supports_workflow_dictation": true,
"supports_streaming": true,
"supports_translation": true
}status is ready when the selected model can transcribe and no_model otherwise. Capability fields describe the currently selected engine; nullable engine and model values are omitted when none is selected.
Transcribe audio
curl -X POST http://localhost:8978/v1/transcribe \ -F "file=@recording.wav" \ -F "language_hint=de" \ -F "language_hint=en" \ -F "response_format=verbose_json"
{
"text": "Hello, world!",
"language": "en",
"duration": 2.5,
"processing_time": 0.8,
"engine": "whisper",
"model": "openai_whisper-large-v3_turbo",
"segments": [
{ "start": 0, "end": 2.5, "text": "Hello, world!" }
]
}Upload limit: Multipart and raw-body uploads to /v1/transcribe are limited to 256 MiB. Larger requests return 413 Payload Too Large. The macOS CLI uses the local-file route for file paths, while stdin remains subject to this limit.
Multipart parameters
language– An exact language code such as en or de. Omit it for automatic detection; do not combine it with language_hint.language_hint– A repeatable, ordered shortlist for restricted automatic detection. Hint-aware engines receive the full list; other engines use the first hint.task– transcribe (default) or translate. The translate task translates into English and requires WhisperKit.target_language– A target language code for a separate Apple Translate step. This requires macOS 15 or later.response_format– json (default) or verbose_json. Verbose output adds timestamped segments and optional speaker metadata when the engine provides it.prompt– A request-specific transcription prompt. TypeWhisper combines it with enabled Dictionary terms.engine/model– Per-request engine/model overrides. A model alone is inferred only when exactly one engine offers that ID.normalize_numbers– A Boolean override for spoken-number normalization.apply_corrections– A Boolean that defaults to true. Set it to false to return raw engine output without post-transcription Dictionary Corrections.?await_download=1– Wait for an unconfigured local engine to restore or download its model instead of returning 409 immediately.
Raw-body uploads use the Content-Type to infer the audio format and the corresponding X-Language, X-Language-Hints, X-Task, X-Target-Language, X-Response-Format, X-Prompt, X-Engine, X-Model, X-Normalize-Numbers, and X-Apply-Corrections headers for options.
POST /v1/transcribe/local-file accepts a JSON body with an absolute path and the same snake_case options. It is only useful for files readable by the local TypeWhisper process and is not a remote file API.
List models
curl http://localhost:8978/v1/models
{
"models": [
{
"id": "openai_whisper-large-v3_turbo",
"engine": "whisper",
"name": "Large v3 Turbo",
"size_description": "~800 MB",
"language_count": 99,
"status": "ready",
"selected": true,
"downloaded": true,
"loaded": true
}
]
}status is ready or not_configured. selected identifies the current GUI selection; downloaded and loaded are included when the engine can report those states.
History
curl "http://localhost:8978/v1/history?q=meeting&limit=10&offset=0" curl -X DELETE "http://localhost:8978/v1/history?id=<uuid>"
q is optional. limit defaults to 50 and is capped at 200; offset defaults to 0. Results include final and raw text, ISO 8601 timestamp, app context, duration, language, engine, model, and word count.
Dictionary
Recognition terms influence transcription. Dictionary Corrections run after transcription and rewrite matching text unless apply_corrections is false.
curl http://localhost:8978/v1/dictionary/terms
curl -X PUT http://localhost:8978/v1/dictionary/terms \
-H "Content-Type: application/json" \
-d '{"term_entries":[{"term":"TypeWhisper","ctc_min_similarity":0.65}],"replace":false}'
curl -X DELETE http://localhost:8978/v1/dictionary/terms \
-H "Content-Type: application/json" \
-d '{"term":"TypeWhisper"}'For simple terms, send a terms string array. For Parakeet CTC tuning, send term_entries with optional ctc_min_similarity. Set replace to true to replace all existing recognition terms; otherwise entries are merged.
curl http://localhost:8978/v1/dictionary/corrections
curl -X PUT http://localhost:8978/v1/dictionary/corrections \
-H "Content-Type: application/json" \
-d '{"original":"teh","replacement":"the","caseSensitive":false}'
curl -X DELETE http://localhost:8978/v1/dictionary/corrections \
-H "Content-Type: application/json" \
-d '{"original":"teh"}'Settings Backup: API and CLI
The API uses the same schema as Settings > Advanced > Backup & Restore. Export includes all supported categories: workflows, Dictionary entries, snippets, prompt actions, profiles, hotkeys, non-bundled plugins, history, update channel, and preferences.
DISCOVERY="$HOME/Library/Application Support/TypeWhisper/api-discovery.json"
TYPEWHISPER_API_PORT="$(jq -r '.port' "$DISCOVERY")"
TYPEWHISPER_API_TOKEN="$(jq -r '.token' "$DISCOVERY")"
(
settings_backup_tmp="$(mktemp ./typewhisper-settings.json.tmp.XXXXXX)" || exit
trap 'rm -f "$settings_backup_tmp"' EXIT
curl --fail --silent --show-error \
"http://localhost:$TYPEWHISPER_API_PORT/v1/settings/export" \
-H "Authorization: Bearer $TYPEWHISPER_API_TOKEN" \
--output "$settings_backup_tmp" && \
mv "$settings_backup_tmp" typewhisper-settings.json
) && \
curl --fail --silent --show-error -X POST \
"http://localhost:$TYPEWHISPER_API_PORT/v1/settings/import" \
-H "Authorization: Bearer $TYPEWHISPER_API_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @typewhisper-settings.jsonImport applies all categories in the document using the existing merge/skip rules. It does not wipe the destination Mac first: workflows and profiles are appended, duplicates can be skipped, occupied hotkey slots are preserved, unavailable or installed plugins are skipped, and history outside the destination retention window is omitted.
Import response
{
"workflowsImported": 4,
"dictionaryImported": 52,
"dictionarySkipped": 3,
"snippetsImported": 6,
"snippetsSkipped": 1,
"promptActionsImported": 2,
"profilesImported": 2,
"hotkeysApplied": 1,
"hotkeysSkipped": 1,
"pluginsInstalled": 2,
"pluginsSkipped": 1,
"pluginsRegistryFetchFailed": false,
"historyImported": 120,
"historySkippedByRetention": 8,
"updateChannelApplied": true,
"preferencesApplied": 27
}CLI commands
Install the CLI in Settings > Advanced > Command Line Tool. export writes the API backup atomically; import accepts relative, absolute, and tilde-expanded paths. Add --json for a machine-readable export receipt or import summary.
mkdir -p ~/.config/typewhisper typewhisper export ~/.config/typewhisper/settings.json typewhisper import ~/.config/typewhisper/settings.json typewhisper import ~/.config/typewhisper/settings.json --json
A backup can contain transcription history, prompts, app/website rules, and other personal configuration. Review it before committing it to a dotfiles repository. The implementation adds explicit import/export commands; it does not automatically load $XDG_CONFIG_HOME/typewhisper/config.toml.
Workflow-backed rules
curl http://localhost:8978/v1/rules curl -X PUT "http://localhost:8978/v1/rules/toggle?id=<uuid>"
Each entry includes its UUID, enabled state, priority, app bundle identifiers, URL patterns, language mode and hints, and optional translation target. Use a rule UUID as workflow_id when starting dictation with a forced workflow.
Legacy compatibility: /v1/profiles and /v1/profiles/toggle remain available as exact aliases for older integrations.
Dictation control
These routes use TypeWhisper's system-wide dictation pipeline and insertion behavior. Start returns a session UUID; stop returns the same UUID so a script can poll its result.
curl -X POST http://localhost:8978/v1/dictation/start \
-H "Content-Type: application/json" \
-d '{"workflow_id":"<uuid>"}'
curl -X POST http://localhost:8978/v1/dictation/stop
curl http://localhost:8978/v1/dictation/status
curl "http://localhost:8978/v1/dictation/transcription?id=<uuid>"The start body is optional. When workflow_id is supplied, it must name an existing enabled workflow; TypeWhisper returns the selected workflow ID and name in the start response.
Poll /v1/dictation/transcription until status becomes completed or failed. A completed response contains both final and raw text plus timestamp, app context, duration, language, engine, model, and word count.
Recorder control
Recorder creates a saved recording and can capture microphone, system audio, or both. It follows the same mixing, finalization, and optional transcription path as the Recorder UI without pasting text into another app.
curl -X POST "http://localhost:8978/v1/recorder/start?mic=true&system_audio=true" curl -X POST http://localhost:8978/v1/recorder/stop curl http://localhost:8978/v1/recorder/status curl "http://localhost:8978/v1/recorder/session?id=<uuid>"
mic and system_audio accept true, false, 1, or 0. Omitted values inherit the current Recorder settings, and at least one resolved source must remain enabled.
{
"id": "8F8C1F45-6D03-44D2-A38C-0C4DE4F7E5F7",
"status": "completed",
"text": "Meeting notes from the recording.",
"output_file": "/Users/alex/Documents/TypeWhisper Recordings/Recording.m4a"
}Sessions move through recording, finalizing, and completed or failed. text is omitted when transcription is disabled or empty; output_file is returned when a recording was finalized, and failed sessions include error.
Error responses
Failures use a nested JSON error object with code and message fields. Handle the HTTP status first and use message for detail:
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API token"
}
}Common HTTP statuses
400– Missing or invalid body, query parameter, file, audio format, workflow ID, or option value.401– Require API Token is enabled and the request has no valid Bearer or X-TypeWhisper-API-Token value.404– A requested history entry, rule, workflow, dictation session, or Recorder session does not exist.409– The requested recording state conflicts with the current state, or an overridden engine is not configured.413– The request body exceeds the 256 MiB upload limit.501– Target-language translation was requested on a macOS version before 15.503– No transcription engine is selected.500– An internal transcription, Dictionary, settings backup, or session error occurred. Check the app logs or diagnostics export for detail.