Local API
WhisperTyping includes a Local API that lets you integrate voice typing into your own projects. We believe there are a lot of possibilities here: connecting WhisperTyping to Stream Decks, home automation, AI agents, accessibility tools, and things we haven't even thought of yet. This is a work in progress, and we're always expanding it. If you build something cool with it, we'd love to hear about your project.
The API has two parts. The Command API lets you send commands to WhisperTyping via HTTP requests: control recording, change settings, manage your vocabulary and text replacements, and more. The Transcription Hook works the other way around: WhisperTyping sends each transcription to a service you specify, so you can intercept voice commands, process text, or trigger automations before anything is typed.
The Command API listens on port 39849 on localhost. The Transcription Hook sends requests to whatever URL you configure, which can be a local service or a remote server anywhere on the internet.
Base URL: http://localhost:39849
Table of Contents
Getting Started
The Local API is enabled by default. You can test it right away by opening a terminal and running:
# See all available endpoints
curl http://localhost:39849/
# Check app status
curl http://localhost:39849/api/status
# Start recording
curl -X POST http://localhost:39849/api/recording/start
# Stop recording (transcribes the audio)
curl -X POST http://localhost:39849/api/recording/stop
The base URL (http://localhost:39849/) returns the app version, current state, a link to this documentation, and a list of all available endpoints. This is a good starting point to verify the API is running and to discover what's available.
You can also call the API from JavaScript in the browser using fetch(). Browser requests are blocked by default for security. To allow browser access, go to Settings → Advanced and add your origin to "Allowed browser origins" (e.g. http://localhost:3000), or use * to allow all origins.
All endpoints return JSON:
{ "success": true }
If something goes wrong:
{ "success": false, "error": "Not currently recording" }
Settings
You can configure the Local API in Settings → Advanced:
* to allow all, or list specific origins separated by commas (e.g. http://localhost:3000). Scripts and desktop applications are always allowed.
Command API
Status
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/status | Get current app status |
Response:
{
"success": true,
"recording": false,
"state": "idle",
"model": "Whisper Ultra",
"language": "en",
"toolbar": "compact",
"version": "4.4.5"
}
The state field is one of: idle, recording, processing.
Recording
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /api/recording/start | Start recording (dictation) |
| GET/POST | /api/recording/stop | Stop recording and transcribe |
| GET/POST | /api/recording/cancel | Cancel current recording without transcribing |
| GET/POST | /api/recording/toggle | Toggle: starts if idle, stops if recording |
Recording started via the API works the same as recording started via a hotkey. Your AI mode, language, text replacements, and all other settings apply normally.
Request:
curl -X POST http://localhost:39849/api/recording/start
Response:
{ "success": true }
Error response (already recording):
{ "success": false, "error": "Cannot start recording - currently recording" }
Model
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/model | Get current model and available options |
| POST | /api/model | Change transcription model |
GET response:
{
"success": true,
"model": "Whisper Ultra",
"options": ["Whisper Large", "Whisper Ultra", "Ultra Medical (English)"]
}
The available options depend on your subscription tier. To change the model:
POST request:
curl -X POST http://localhost:39849/api/model \
-H "Content-Type: application/json" \
-d '{ "model": "Whisper Large" }'
POST response:
{ "success": true, "model": "Whisper Large" }
Language
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/language | Get current language and available options |
| POST | /api/language | Change language |
GET response:
{
"success": true,
"language": "en",
"model": "Whisper Ultra",
"options": [
{ "code": "", "name": "Auto-Detect" },
{ "code": "en", "name": "English" },
{ "code": "nl", "name": "Dutch" }
]
}
Available languages depend on the current model. Most models support 51 languages plus auto-detect. Medical models only support English variants. Use an empty string "" for auto-detect.
POST request:
curl -X POST http://localhost:39849/api/language \
-H "Content-Type: application/json" \
-d '{ "language": "nl" }'
POST response:
{ "success": true, "language": "nl", "model": "Whisper Ultra" }
Toolbar
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/toolbar | Get current toolbar mode and options |
| POST | /api/toolbar | Change toolbar mode |
Three modes are available:
full– Full-size toolbar, window visiblecompact– Compact toolbar, window visiblehidden– Minimized to system tray
POST request:
curl -X POST http://localhost:39849/api/toolbar \
-H "Content-Type: application/json" \
-d '{ "mode": "compact" }'
POST response:
{ "success": true, "toolbar": "compact" }
Vocabulary
The vocabulary is a list of words and phrases that helps the speech recognition model transcribe them correctly. This is especially useful for proper names, technical terms, abbreviations, and domain-specific jargon.
A vocabulary entry can be a single word or a multi-word phrase. For example, Dr. Smith, Microsoft Azure, or amoxicillin are all valid entries. The vocabulary is stored as a comma-separated string internally.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/vocabulary | Get the current vocabulary |
| POST | /api/vocabulary | Set the entire vocabulary (replaces all) |
| POST | /api/vocabulary/add | Add words to the vocabulary (skips duplicates) |
| POST | /api/vocabulary/remove | Remove words from the vocabulary |
Get Vocabulary
curl http://localhost:39849/api/vocabulary
Response:
{
"success": true,
"vocabulary": "Dr. Smith, amoxicillin, WhisperTyping",
"words": ["Dr. Smith", "amoxicillin", "WhisperTyping"],
"characterCount": 39,
"characterLimit": 500
}
vocabulary– The raw comma-separated string as stored in settings.words– The vocabulary split into individual entries (trimmed).characterCount– Current length of the vocabulary string.characterLimit– Maximum characters allowed (depends on the current model).
Set Vocabulary
Replaces the entire vocabulary with a new value.
curl -X POST http://localhost:39849/api/vocabulary \
-H "Content-Type: application/json" \
-d '{ "vocabulary": "Dr. Smith, amoxicillin, WhisperTyping" }'
Response: Returns the same format as GET (the new vocabulary state).
Add Words
Adds new entries to the existing vocabulary. Duplicates are skipped (case-insensitive comparison). Each entry in the words array can be a single word or a multi-word phrase.
curl -X POST http://localhost:39849/api/vocabulary/add \
-H "Content-Type: application/json" \
-d '{ "words": ["John Williams", "penicillin", "WhisperTyping"] }'
Response:
{
"success": true,
"added": ["John Williams", "penicillin"],
"skipped": ["WhisperTyping"],
"vocabulary": "Dr. Smith, amoxicillin, WhisperTyping, John Williams, penicillin",
"characterCount": 62,
"characterLimit": 500
}
added– Words that were added (not already present).skipped– Words that were already in the vocabulary (case-insensitive).
Remove Words
Removes entries from the vocabulary. Matching is case-insensitive.
curl -X POST http://localhost:39849/api/vocabulary/remove \
-H "Content-Type: application/json" \
-d '{ "words": ["amoxicillin", "nonexistent"] }'
Response:
{
"success": true,
"removed": ["amoxicillin"],
"notFound": ["nonexistent"],
"vocabulary": "Dr. Smith, WhisperTyping, John Williams, penicillin",
"characterCount": 50,
"characterLimit": 500
}
Screen OCR
When Screen OCR is enabled, WhisperTyping reads text from the active window before each recording and uses it to improve transcription accuracy. This helps with names, numbers, and context-specific terms visible on screen.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/ocr | Check if Screen OCR is enabled |
| POST | /api/ocr | Enable or disable Screen OCR |
Get OCR Status
curl http://localhost:39849/api/ocr
Response:
{ "success": true, "enabled": false }
Enable/Disable OCR
curl -X POST http://localhost:39849/api/ocr \
-H "Content-Type: application/json" \
-d '{ "enabled": true }'
Response:
{ "success": true, "enabled": true }
Microphones
List available microphone devices and select which one WhisperTyping should use for recording.
List microphones
GET /api/microphones
Returns all audio input devices detected by the system.
Example:
curl http://localhost:39849/api/microphones
Response:
{
"success": true,
"microphones": [
{ "id": null, "name": "Default", "isDefault": true, "isAvailable": true },
{ "id": "{0.0.1.00000000}.{abc...}", "name": "Headset (EarPods)", "isDefault": true, "isAvailable": true },
{ "id": "{0.0.1.00000000}.{def...}", "name": "Microphone (NVIDIA Broadcast)", "isDefault": false, "isAvailable": true }
],
"count": 3
}
Each microphone includes:
id– The Windows device ID, ornullfor the Default entry.name– Friendly name as shown in Windows Sound settings.isDefault– Whether this is the current Windows default recording device.isAvailable– Whether the device is currently connected and active.
Set microphone
To change the microphone, use the preferredMicrophone setting. The API accepts flexible input and resolves it to a specific device:
- Full device ID – e.g.
"{0.0.1.00000000}.{abc...}" - Exact device name – e.g.
"Headset (EarPods)" - Partial name – e.g.
"EarPods"or"NVIDIA". Works as long as it matches exactly one device. - Empty string or "default" – Resets to the system default microphone.
Example:
curl -X POST http://localhost:39849/api/settings/preferredMicrophone \
-H "Content-Type: application/json" \
-d '{ "value": "EarPods" }'
Response:
{
"success": true,
"key": "preferredMicrophone",
"value": "{0.0.1.00000000}.{abc...}|Headset (EarPods)",
"previousValue": "",
"resolvedDevice": { "id": "{0.0.1.00000000}.{abc...}", "name": "Headset (EarPods)" }
}
If the name matches multiple devices, the API returns an error listing the ambiguous matches so you can be more specific. If no device matches, it returns the full list of available microphones.
App Settings
Read and write application settings programmatically. This gives you full control over preferences, advanced options, hotkeys, mobile settings, and more.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/settings | Get all settings with current values, types, and options |
| GET | /api/settings/{key} | Get a single setting by key |
| POST | /api/settings/{key} | Update a single setting |
| POST | /api/settings | Update multiple settings at once |
Setting Object
Each setting includes these fields:
key– The setting identifier, used in the URL for get/set operations.value– The current value.type– Data type:bool,int,double, orstring.label– Human-readable description.page– The settings page where this appears in the UI (advanced, preferences, hotkeys, microphone, history, mobile, vocabulary).options– (only for settings with a fixed set of valid values) An array of allowed values.
Get All Settings
curl http://localhost:39849/api/settings
Response (shortened for brevity):
{
"success": true,
"settings": [
{
"key": "pasteDelayMs",
"value": 25,
"type": "int",
"label": "Paste delay (ms)",
"page": "advanced"
},
{
"key": "toolbarVisibility",
"value": "WhileRecording",
"type": "string",
"label": "Toolbar always-on-top behavior",
"page": "preferences",
"options": ["WhileRecording", "Always", "Never"]
}
],
"count": 38
}
Get a Single Setting
curl http://localhost:39849/api/settings/toolbarVisibility
Response:
{
"success": true,
"key": "toolbarVisibility",
"value": "WhileRecording",
"type": "string",
"label": "Toolbar always-on-top behavior",
"page": "preferences",
"options": ["WhileRecording", "Always", "Never"]
}
If the setting is unknown, the response includes a list of all available setting keys:
{
"success": false,
"error": "Unknown setting: badKey",
"availableSettings": ["windowOCR", "convertSpokenPunctuation", "..."]
}
Update a Single Setting
curl -X POST http://localhost:39849/api/settings/pasteDelayMs \
-H "Content-Type: application/json" \
-d '{ "value": 50 }'
Response:
{
"success": true,
"key": "pasteDelayMs",
"value": 50,
"previousValue": 25
}
The response includes both the new value and the previous value, so you can easily undo changes. Values are validated before saving:
// Wrong type
{ "success": false, "error": "Expected boolean value for \"history\"" }
// Invalid option
{
"success": false,
"error": "Invalid value for \"recordingMediaAction\". Options: None, Reduce50, Reduce75, Reduce90, Mute",
"options": ["None", "Reduce50", "Reduce75", "Reduce90", "Mute"]
}
Update Multiple Settings
Set multiple settings in a single request. All valid settings are applied, even if some fail validation.
curl -X POST http://localhost:39849/api/settings \
-H "Content-Type: application/json" \
-d '{
"settings": {
"soundEffect": false,
"pasteDelayMs": 50,
"toolbarVisibility": "Always"
}
}'
Response:
{
"success": true,
"updated": [
{ "key": "soundEffect", "value": false, "previousValue": true },
{ "key": "pasteDelayMs", "value": 50, "previousValue": 25 },
{ "key": "toolbarVisibility", "value": "Always", "previousValue": "WhileRecording" }
]
}
If some settings fail validation, success is false and the errors are reported separately. The valid settings are still applied:
{
"success": false,
"updated": [
{ "key": "soundEffect", "value": false, "previousValue": true }
],
"errors": [
{ "key": "badKey", "error": "Unknown setting" }
]
}
Available Settings
The full list of settings is always available via GET /api/settings. Below is a reference of all settings organized by page.
Advanced
| Key | Type | Default | Description |
|---|---|---|---|
convertSpokenPunctuation | bool | true | Convert spoken words like "full stop" and "comma" to punctuation symbols. |
convertEmoji | bool | true | Convert spoken emoji names to emoji symbols (English only). |
noPunctuationForShortSegments | bool | true | Remove trailing period from short phrases (5 words or less). |
autoSpacing | bool | true | Automatically add a space between successive transcriptions. |
pasteDelayMs | int | 25 | Delay in milliseconds before pasting text (increase if pasting is unreliable). |
enterDelayMs | int | 150 | Delay in milliseconds between paste and Enter key press. |
doubleUnlockAddsEnter | bool | true | Double-tap the lock key to add an Enter after the transcription. |
recordingMediaAction | string | "None" | Control media volume during recording. Options: None, Reduce50, Reduce75, Reduce90, Mute. |
connectionProtocol | string | "Auto" | Internet protocol for server connections. Options: Auto, IPv4, IPv6. |
streamAudio | bool | false | Stream audio during recording instead of uploading after. Helps on unstable connections. |
forceSoftwareRendering | bool | false | Use software rendering instead of GPU acceleration. |
localApiEnabled | bool | true | Enable or disable the Local API server. Note: disabling this via the API will shut down the server. You can only re-enable it from the application settings UI. |
localApiAllowedOrigins | string | "" | CORS allowed origins for browser access. Empty = block all, * = allow all, or comma-separated list. |
transcriptionHookUrl | string | "" | Webhook URL that receives transcriptions before typing. Empty = disabled. |
transcriptionHookTimeoutMs | int | 2000 | Timeout in milliseconds for the transcription webhook. |
Preferences
| Key | Type | Default | Description |
|---|---|---|---|
showInTaskbar | bool | true | Show WhisperTyping in the Windows taskbar. |
compact | bool | false | Use compact (smaller) toolbar mode. |
toolbarVisibility | string | "WhileRecording" | When the toolbar stays on top. Options: WhileRecording, Always, Never. |
windowScale | double | 1.0 | Toolbar zoom/size multiplier. |
backgroundColor | string | "" | Custom toolbar background color in hex format (e.g. #FF4189AC). Empty = default. |
startMinimized | bool | false | Start the application minimized to the system tray. |
runOnStartup | bool | false | Automatically launch WhisperTyping when Windows starts. |
soundEffect | bool | true | Play audio cues when starting and stopping recording. |
engagementReminders | bool | false | Show progress and statistics reminder notifications. |
Hotkeys
| Key | Type | Default | Description |
|---|---|---|---|
keyboardKeys | string | "None" | Primary hold-to-record key combination. |
lockKeys | string | "" | Toggle recording key (tap to start/stop). |
secondaryLockKeys | string | "" | Secondary toggle recording key. |
pasteKeys | string | "Ctrl+Alt+V" | Hotkey to re-paste the last transcription output. |
mouseWheelActivation | bool | false | Use the mouse wheel button to start/stop recording. |
dictationMicEnabled | bool | false | Enable support for dedicated dictation microphones (e.g. Nuance PowerMic). |
Vocabulary
| Key | Type | Default | Description |
|---|---|---|---|
windowOCR | bool | false | Use OCR to extract vocabulary from the active window before each recording. |
History
| Key | Type | Default | Description |
|---|---|---|---|
history | bool | true | Save transcriptions to the local history database. |
Microphone
| Key | Type | Default | Description |
|---|---|---|---|
preferredMicrophone | string | "" | Preferred microphone. Accepts a device ID, full name, or partial name (e.g. "EarPods"). Empty or "default" = system default. See Microphones. |
Mobile
| Key | Type | Default | Description |
|---|---|---|---|
mobileDictationEnabled | bool | false | Enable mobile phone microphone feature. |
mobileBufferHistoryCount | int | 25 | Number of transcriptions to display. Options: 1, 5, 25, 100. |
mobileBufferSpacing | string | "2 enters" | Spacing between transcriptions. Options: From Phone, None, 1 enter, 2 enters. |
mobileRecordingNotification | bool | false | Show a tray notification when a mobile recording is received. |
autoOpenVoiceNotes | bool | true | Automatically open the Voice Notes window when a voice note is received. |
Text Replacements
Text replacements automatically transform spoken text after transcription. For example, you can replace "my email" with your actual email address, or fix common transcription errors. Replacements are applied in order, so the position matters.
Each replacement has a unique id for stable referencing. The id is auto-generated and never changes, even when replacements are reordered.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/replacements | Get all text replacements |
| POST | /api/replacements | Set all text replacements (replaces entire list) |
| POST | /api/replacements/add | Add a new replacement |
| GET | /api/replacements/{id} | Get a single replacement by id |
| POST | /api/replacements/{id}/update | Update a replacement (partial update) |
| POST | /api/replacements/{id}/delete | Delete a replacement |
| POST | /api/replacements/{id}/move | Move a replacement to a new position |
Replacement Object
Each replacement has the following fields:
| Field | Type | Default | Description |
|---|---|---|---|
id | string | (auto) | Unique identifier (auto-generated, read-only). |
position | integer | (auto) | Position in the list (0-based, read-only). |
match | string[] | [] | One or more patterns to match. Multiple entries act as aliases (any of them will trigger the replacement). |
replace | string | "" | The replacement text. |
scope | string | "Anywhere" | Where to match: Anywhere, WholeWord, StartOnly, or EndOnly. |
preserveCase | boolean | false | If true, the replacement preserves the case of the matched text (ALL CAPS, lowercase, Title Case). |
includeVariants | boolean | false | If true, also matches variations with separators (e.g. "hash-tag" and "hash tag" both match "hashtag"). |
swallowPunctuations | boolean | false | If true, punctuation immediately following the matched text is removed. |
isRegex | boolean | false | If true, the match pattern is treated as a regular expression instead of literal text. |
enabled | boolean | true | If false, the replacement is skipped during processing. |
Get All Replacements
curl http://localhost:39849/api/replacements
Response:
{
"success": true,
"replacements": [
{
"id": "a1b2c3d4e5f6789012345678abcdef01",
"position": 0,
"match": ["my email"],
"replace": "john@example.com",
"scope": "WholeWord",
"preserveCase": false,
"includeVariants": false,
"swallowPunctuations": false,
"isRegex": false,
"enabled": true
},
{
"id": "fedcba9876543210fedcba9876543210",
"position": 1,
"match": ["hashtag", "hash tag"],
"replace": "#",
"scope": "Anywhere",
"preserveCase": false,
"includeVariants": true,
"swallowPunctuations": false,
"isRegex": false,
"enabled": true
}
],
"count": 2
}
Set All Replacements
Replaces the entire replacement list. Any replacement without an id gets one auto-assigned. Useful for bulk configuration.
curl -X POST http://localhost:39849/api/replacements \
-H "Content-Type: application/json" \
-d '{
"replacements": [
{
"match": ["my email"],
"replace": "john@example.com",
"scope": "WholeWord",
"enabled": true
},
{
"match": ["my phone"],
"replace": "+1 555-0123",
"scope": "WholeWord",
"enabled": true
}
]
}'
Response: Returns the same format as GET (the full list with auto-assigned ids).
Add a Replacement
Adds a single replacement to the end of the list. An id is auto-generated. Only match is required; all other fields use their defaults if omitted.
curl -X POST http://localhost:39849/api/replacements/add \
-H "Content-Type: application/json" \
-d '{
"match": ["my address"],
"replace": "123 Main Street, Springfield",
"scope": "WholeWord"
}'
Response:
{
"success": true,
"replacement": {
"id": "01234567890abcdef01234567890abcd",
"position": 2,
"match": ["my address"],
"replace": "123 Main Street, Springfield",
"scope": "WholeWord",
"preserveCase": false,
"includeVariants": false,
"swallowPunctuations": false,
"isRegex": false,
"enabled": true
}
}
Get a Single Replacement
curl http://localhost:39849/api/replacements/a1b2c3d4e5f6789012345678abcdef01
Response:
{
"success": true,
"replacement": {
"id": "a1b2c3d4e5f6789012345678abcdef01",
"position": 0,
"match": ["my email"],
"replace": "john@example.com",
"scope": "WholeWord",
"preserveCase": false,
"includeVariants": false,
"swallowPunctuations": false,
"isRegex": false,
"enabled": true
}
}
Update a Replacement
Updates specific fields of an existing replacement. Only include the fields you want to change. Fields not included keep their current value.
curl -X POST http://localhost:39849/api/replacements/a1b2c3d4e5f6789012345678abcdef01/update \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'
Response:
{
"success": true,
"replacement": {
"id": "a1b2c3d4e5f6789012345678abcdef01",
"position": 0,
"match": ["my email"],
"replace": "john@example.com",
"scope": "WholeWord",
"preserveCase": false,
"includeVariants": false,
"swallowPunctuations": false,
"isRegex": false,
"enabled": false
}
}
You can update multiple fields at once:
curl -X POST http://localhost:39849/api/replacements/a1b2c3d4e5f6789012345678abcdef01/update \
-H "Content-Type: application/json" \
-d '{ "replace": "jane@example.com", "match": ["my email", "email address"] }'
Delete a Replacement
curl -X POST http://localhost:39849/api/replacements/a1b2c3d4e5f6789012345678abcdef01/delete
Response:
{ "success": true }
Error (not found):
{ "success": false, "error": "Replacement not found: a1b2c3d4e5f6789012345678abcdef01" }
Move a Replacement
Moves a replacement to a new position in the list. Positions are 0-based. The position is clamped to the valid range.
curl -X POST http://localhost:39849/api/replacements/fedcba9876543210fedcba9876543210/move \
-H "Content-Type: application/json" \
-d '{ "position": 0 }'
Response:
{
"success": true,
"replacement": {
"id": "fedcba9876543210fedcba9876543210",
"position": 0,
"match": ["hashtag", "hash tag"],
"replace": "#",
"scope": "Anywhere",
"preserveCase": false,
"includeVariants": true,
"swallowPunctuations": false,
"isRegex": false,
"enabled": true
}
}
Transcription Hook Configuration
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/hook | Get current hook URL |
| POST | /api/hook | Set or clear the hook URL |
Get Hook Config
curl http://localhost:39849/api/hook
Response:
{ "success": true, "url": "http://localhost:8585/hook", "enabled": true }
Set Hook URL
curl -X POST http://localhost:39849/api/hook \
-H "Content-Type: application/json" \
-d '{ "url": "http://localhost:8585/hook" }'
Response:
{ "success": true, "url": "http://localhost:8585/hook", "enabled": true }
Set an empty string to disable the hook:
curl -X POST http://localhost:39849/api/hook \
-H "Content-Type: application/json" \
-d '{ "url": "" }'
Output Window
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/window/output | Get available icon names |
| POST | /api/window/output | Display content in the output window |
Display custom content in WhisperTyping's output window. This brings the window to the foreground. All fields are optional, but at least title or content must be provided.
POST request:
curl -X POST http://localhost:39849/api/window/output \
-H "Content-Type: application/json" \
-d '{ "title": "Home", "icon": "home", "content": "Lights turned off." }'
Response:
{ "success": true }
The icon field is optional. If omitted, a default icon is used. Available icons: microphone, edit, comment, terminal, reply, question, check, info, warning, error, home, lightbulb, gear, search, bolt, star, heart, flag, bell, clipboard, keyboard, play, globe, code, link.
Settings Pages
Open specific settings pages in the WhisperTyping window.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/window/settings/general | Open Settings → General |
| POST | /api/window/settings/microphone | Open Settings → Microphone |
| POST | /api/window/settings/hotkeys | Open Settings → Hotkeys |
| POST | /api/window/settings/vocabulary | Open Settings → Vocabulary |
| POST | /api/window/settings/replacements | Open Settings → Replacements |
| POST | /api/window/settings/aimodes | Open Settings → AI Modes |
| POST | /api/window/settings/appearance | Open Settings → Appearance |
| POST | /api/window/settings/history | Open Settings → History |
| POST | /api/window/settings/advanced | Open Settings → Advanced |
| POST | /api/window/settings/mobile | Open Settings → Mobile |
Request:
curl -X POST http://localhost:39849/api/window/settings/vocabulary
Response:
{ "success": true, "page": "vocabulary" }
Exit
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/exit | Shut down WhisperTyping |
curl -X POST http://localhost:39849/api/exit
Response:
{ "success": true }
Transcription Hook
The transcription hook lets an external service receive every transcription before it is typed. Your service decides what happens: let the text through normally, or intercept it and optionally display output in WhisperTyping's window.
This enables use cases like home automation voice commands, AI agents, custom command systems, logging, and more.
How It Works
The hook fires after text replacements and spoken punctuation are applied, but before AI mode processing:
Pipeline: Speech → Transcribe → Replacements & Punctuation → Hook → AI Mode → Virtual Keyboard
Configure the hook URL in Settings → Advanced under "Transcription hook URL", or via the API (POST /api/hook).
What Your Service Receives
WhisperTyping sends a POST request with JSON for each transcription:
POST http://your-service-url
Content-Type: application/json
{
"text": "Turn off all the lights in my office.",
"verbatim": "turn off all the lights in my office",
"timestamp": "2026-02-21T12:00:00.000Z",
"language": "en"
}
text– The transcription after text replacements and spoken punctuation. This is what would be typed.verbatim– The original transcription exactly as it came from the speech-to-text engine, before any processing.
How to Respond
Your service responds with a JSON object. All fields are optional. An empty response {} lets the text through normally.
| Field | Type | Default | Description |
|---|---|---|---|
intercept | boolean | false | If true, the text is blocked. Nothing is typed and no AI mode is applied. |
skip_ai | boolean | false | If true, AI mode processing is skipped. The text goes directly to the virtual keyboard. Has no effect when intercept is true. |
text | string | null | Override the transcription text. The overridden text continues through the rest of the pipeline (AI mode, virtual keyboard). If null or absent, the original text is used. |
title | string | null | Title text shown in the WhisperTyping output window header. |
icon | string | null | Icon shown in the output window header. See available icons. If omitted, a default icon is used. |
content | string | null | Body text shown in the output window panel. |
If title or content is provided, the WhisperTyping output window is brought to the foreground and displays the content. This works with any combination of flags.
Examples
Let it through (default):
{}
WhisperTyping continues normally: applies AI mode if active, then types the text.
Override the text:
{ "text": "The corrected transcription text." }
Replaces the transcription text with a new value. The overridden text continues through the pipeline normally (AI mode, virtual keyboard). Useful for fixing transcription errors, translating, or preprocessing text before it's typed.
Intercept and show output:
{
"intercept": true,
"title": "Home Automation",
"icon": "home",
"content": "Lights turned off in the office."
}
The text is blocked and a message is displayed in the output window.
Skip AI mode:
{ "skip_ai": true }
The text is typed directly, bypassing AI mode. Useful when your service has already processed the text.
Timeout
The default timeout is 30 seconds. If your service doesn't respond in time, WhisperTyping continues normally and types the text. While waiting for a response, the app shows "Handling" status.
Security
The Local API is designed to be safe by default:
- Localhost only. The server only accepts connections from your own computer. Other devices on your network cannot reach it.
- Browser requests are blocked by default. Websites cannot control WhisperTyping unless you explicitly allow their origin in settings. This prevents malicious websites from accessing the API.
- Local applications are always allowed. Scripts, automation tools, and desktop apps running on your machine can always use the API. This is by design: software already running on your computer could simulate keyboard input anyway.
Allowing Browser Access
If you're building a web-based dashboard or control panel that runs in your browser, you'll need to add its origin to the allowed list in Settings → Advanced. For example, if your dashboard runs at http://localhost:3000, add that as an allowed origin.
Use Cases
Stream Deck
Map Stream Deck buttons to start, stop, or toggle recording. Switch models or languages with a single button press.
Home Automation
Use the transcription hook to detect voice commands. Say "turn off the lights" and your service sends the command to Home Assistant while intercepting the text so it's not typed.
AI Agents
Build AI-powered agents that receive your transcriptions, understand context, take actions, and display results back in the WhisperTyping window. Agents can also configure vocabulary and text replacements for you.
Custom Scripts
Use Python, PowerShell, Node.js, or any language that supports HTTP to build your own voice-powered workflows and automations.
Get in Touch
We'd love to hear from you. Whether you're integrating WhisperTyping into your software, building a hobby project, or have an idea for a use case we haven't thought of, let us know!
Tell us about your project
What are you building with the Local API? What endpoints would be most useful to you? Your feedback helps us prioritize what to build next.