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:

Enable Local API Master switch to turn the API server on or off. Enabled by default.
Allowed browser origins Controls which websites can access the API. Leave empty to block all browser requests. Enter * to allow all, or list specific origins separated by commas (e.g. http://localhost:3000). Scripts and desktop applications are always allowed.
Transcription hook URL URL to send each transcription to before it is typed. Leave empty to disable. Can also be set via the API.

Command API

Status

MethodEndpointDescription
GET/api/statusGet 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

MethodEndpointDescription
GET/POST/api/recording/startStart recording (dictation)
GET/POST/api/recording/stopStop recording and transcribe
GET/POST/api/recording/cancelCancel current recording without transcribing
GET/POST/api/recording/toggleToggle: 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

MethodEndpointDescription
GET/api/modelGet current model and available options
POST/api/modelChange 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

MethodEndpointDescription
GET/api/languageGet current language and available options
POST/api/languageChange 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

MethodEndpointDescription
GET/api/toolbarGet current toolbar mode and options
POST/api/toolbarChange toolbar mode

Three modes are available:

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.

MethodEndpointDescription
GET/api/vocabularyGet the current vocabulary
POST/api/vocabularySet the entire vocabulary (replaces all)
POST/api/vocabulary/addAdd words to the vocabulary (skips duplicates)
POST/api/vocabulary/removeRemove 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
}

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
}

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.

MethodEndpointDescription
GET/api/ocrCheck if Screen OCR is enabled
POST/api/ocrEnable 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:

Set microphone

To change the microphone, use the preferredMicrophone setting. The API accepts flexible input and resolves it to a specific device:

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.

MethodEndpointDescription
GET/api/settingsGet 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/settingsUpdate multiple settings at once

Setting Object

Each setting includes these fields:

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
KeyTypeDefaultDescription
convertSpokenPunctuationbooltrueConvert spoken words like "full stop" and "comma" to punctuation symbols.
convertEmojibooltrueConvert spoken emoji names to emoji symbols (English only).
noPunctuationForShortSegmentsbooltrueRemove trailing period from short phrases (5 words or less).
autoSpacingbooltrueAutomatically add a space between successive transcriptions.
pasteDelayMsint25Delay in milliseconds before pasting text (increase if pasting is unreliable).
enterDelayMsint150Delay in milliseconds between paste and Enter key press.
doubleUnlockAddsEnterbooltrueDouble-tap the lock key to add an Enter after the transcription.
recordingMediaActionstring"None"Control media volume during recording. Options: None, Reduce50, Reduce75, Reduce90, Mute.
connectionProtocolstring"Auto"Internet protocol for server connections. Options: Auto, IPv4, IPv6.
streamAudioboolfalseStream audio during recording instead of uploading after. Helps on unstable connections.
forceSoftwareRenderingboolfalseUse software rendering instead of GPU acceleration.
localApiEnabledbooltrueEnable 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.
localApiAllowedOriginsstring""CORS allowed origins for browser access. Empty = block all, * = allow all, or comma-separated list.
transcriptionHookUrlstring""Webhook URL that receives transcriptions before typing. Empty = disabled.
transcriptionHookTimeoutMsint2000Timeout in milliseconds for the transcription webhook.
Preferences
KeyTypeDefaultDescription
showInTaskbarbooltrueShow WhisperTyping in the Windows taskbar.
compactboolfalseUse compact (smaller) toolbar mode.
toolbarVisibilitystring"WhileRecording"When the toolbar stays on top. Options: WhileRecording, Always, Never.
windowScaledouble1.0Toolbar zoom/size multiplier.
backgroundColorstring""Custom toolbar background color in hex format (e.g. #FF4189AC). Empty = default.
startMinimizedboolfalseStart the application minimized to the system tray.
runOnStartupboolfalseAutomatically launch WhisperTyping when Windows starts.
soundEffectbooltruePlay audio cues when starting and stopping recording.
engagementRemindersboolfalseShow progress and statistics reminder notifications.
Hotkeys
KeyTypeDefaultDescription
keyboardKeysstring"None"Primary hold-to-record key combination.
lockKeysstring""Toggle recording key (tap to start/stop).
secondaryLockKeysstring""Secondary toggle recording key.
pasteKeysstring"Ctrl+Alt+V"Hotkey to re-paste the last transcription output.
mouseWheelActivationboolfalseUse the mouse wheel button to start/stop recording.
dictationMicEnabledboolfalseEnable support for dedicated dictation microphones (e.g. Nuance PowerMic).
Vocabulary
KeyTypeDefaultDescription
windowOCRboolfalseUse OCR to extract vocabulary from the active window before each recording.
History
KeyTypeDefaultDescription
historybooltrueSave transcriptions to the local history database.
Microphone
KeyTypeDefaultDescription
preferredMicrophonestring""Preferred microphone. Accepts a device ID, full name, or partial name (e.g. "EarPods"). Empty or "default" = system default. See Microphones.
Mobile
KeyTypeDefaultDescription
mobileDictationEnabledboolfalseEnable mobile phone microphone feature.
mobileBufferHistoryCountint25Number of transcriptions to display. Options: 1, 5, 25, 100.
mobileBufferSpacingstring"2 enters"Spacing between transcriptions. Options: From Phone, None, 1 enter, 2 enters.
mobileRecordingNotificationboolfalseShow a tray notification when a mobile recording is received.
autoOpenVoiceNotesbooltrueAutomatically 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.

MethodEndpointDescription
GET/api/replacementsGet all text replacements
POST/api/replacementsSet all text replacements (replaces entire list)
POST/api/replacements/addAdd a new replacement
GET/api/replacements/{id}Get a single replacement by id
POST/api/replacements/{id}/updateUpdate a replacement (partial update)
POST/api/replacements/{id}/deleteDelete a replacement
POST/api/replacements/{id}/moveMove a replacement to a new position

Replacement Object

Each replacement has the following fields:

FieldTypeDefaultDescription
idstring(auto)Unique identifier (auto-generated, read-only).
positioninteger(auto)Position in the list (0-based, read-only).
matchstring[][]One or more patterns to match. Multiple entries act as aliases (any of them will trigger the replacement).
replacestring""The replacement text.
scopestring"Anywhere"Where to match: Anywhere, WholeWord, StartOnly, or EndOnly.
preserveCasebooleanfalseIf true, the replacement preserves the case of the matched text (ALL CAPS, lowercase, Title Case).
includeVariantsbooleanfalseIf true, also matches variations with separators (e.g. "hash-tag" and "hash tag" both match "hashtag").
swallowPunctuationsbooleanfalseIf true, punctuation immediately following the matched text is removed.
isRegexbooleanfalseIf true, the match pattern is treated as a regular expression instead of literal text.
enabledbooleantrueIf 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

MethodEndpointDescription
GET/api/hookGet current hook URL
POST/api/hookSet 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

MethodEndpointDescription
GET/api/window/outputGet available icon names
POST/api/window/outputDisplay 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.

MethodEndpointDescription
POST/api/window/settings/generalOpen Settings → General
POST/api/window/settings/microphoneOpen Settings → Microphone
POST/api/window/settings/hotkeysOpen Settings → Hotkeys
POST/api/window/settings/vocabularyOpen Settings → Vocabulary
POST/api/window/settings/replacementsOpen Settings → Replacements
POST/api/window/settings/aimodesOpen Settings → AI Modes
POST/api/window/settings/appearanceOpen Settings → Appearance
POST/api/window/settings/historyOpen Settings → History
POST/api/window/settings/advancedOpen Settings → Advanced
POST/api/window/settings/mobileOpen Settings → Mobile

Request:

curl -X POST http://localhost:39849/api/window/settings/vocabulary

Response:

{ "success": true, "page": "vocabulary" }

Exit

MethodEndpointDescription
POST/api/exitShut 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"
}

How to Respond

Your service responds with a JSON object. All fields are optional. An empty response {} lets the text through normally.

FieldTypeDefaultDescription
interceptbooleanfalseIf true, the text is blocked. Nothing is typed and no AI mode is applied.
skip_aibooleanfalseIf true, AI mode processing is skipped. The text goes directly to the virtual keyboard. Has no effect when intercept is true.
textstringnullOverride 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.
titlestringnullTitle text shown in the WhisperTyping output window header.
iconstringnullIcon shown in the output window header. See available icons. If omitted, a default icon is used.
contentstringnullBody 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:

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

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.