The Transcription & Captures endpoints power the Captures and Talk tabs in PeachDesk Voice Studio. They turn audio into text (speech-to-text), persist each recording as a capture, and let you re-run transcription or LLM refinement on demand. Speech-to-text runs on PeachDesk’s GPU infrastructure — there is nothing to download or install locally.
These routes are exposed through the PeachDesk API under the /api/voice base path (for example, POST /api/voice/transcribe). Authenticate every request with your PeachDesk API key in the X-API-Key header (an interactive session token in Authorization: Bearer also works — see Authentication).

Authentication

Models

Transcription is served by LIPI, Bibha’s speech-to-text family, running on PeachDesk’s servers. Three models accept a recording on these routes; name one with model / stt_model, or omit it for the default. Live conversational turns are served by LIPI-Fast (lipi-fast), a quantised runtime that decodes while the caller is still speaking. It is selected automatically where its weights are present and is not a value these recording routes accept — pass lipi and the routing is handled for you. See the LIPI family overview.
Model identifiers used before the catalog was consolidated — the legacy size keys base, small, medium, large, and any other pre-consolidation identifier — are still accepted so that saved settings keep loading instead of failing validation. Those models are no longer served: a request naming one is transcribed with LIPI. Don’t use them in new integrations.
Supported language codes: en, zh, ja, ko, de, fr, ru, pt, es, it. Omit language (or pass auto where accepted) to auto-detect.

Transcription

Transcribe an audio file

POST /api/voice/transcribe
One-shot transcription: upload an audio file and receive the recognized text. This does not create a stored capture — use it for stateless transcription. This endpoint accepts multipart/form-data.
file
required
The audio file to transcribe (e.g. WAV, MP3, M4A).
string
Spoken language code. Omit to auto-detect.
string
Transcription model — lipi, lipi-bharat or lipi-live (see Models); the legacy keys listed above are accepted but resolve to lipi. Defaults to the engine’s currently loaded model.
string
transcribe (same-language text) or translate (translate to English). Falls back to your saved capture-settings default when omitted.
integer
Decoding beam size (1–5). Higher values trade speed for accuracy. Falls back to the saved default.
string
Optional bias vocabulary — domain terms, names, or acronyms to nudge the decoder toward. Falls back to the saved default.

Response

string
The transcribed text.
number
Length of the processed audio in seconds.
object
Per-request usage for metering.
If the selected model is still warming up on the server, the endpoint returns 202 Accepted with {"downloading": true, "model_name": "..."}. Wait briefly and retry — the model is being made ready on PeachDesk’s infrastructure; no action is needed on your side.

Live dictation (WebSocket)

WS /api/voice/ws/transcribe/live
Real-time dictation for the Talk tab. The client detects speech with a voice-activity detector and streams each completed utterance as a binary audio frame; the server transcribes it and returns the text so it can be appended to a live transcript.

Protocol

1

Open the socket

Connect to /api/voice/ws/transcribe/live?api_key=bibha_your_api_key (or ?token=<session_token>). WebSocket routes take the credential in the query string — a browser WebSocket cannot set request headers.
2

Send an init frame

The first message is a JSON text frame selecting the language and model:
3

Stream utterances

Send one binary frame per detected utterance (a chunk of audio).
4

Receive segments

For each utterance the server replies with a JSON frame:
On failure it sends { "type": "error", "message": "..." }.
language defaults to en and stt_model defaults to lipi (LIPI) if the init frame omits them. Live dictation uses a low-latency decoding path, so leaving the beam size at 1 (greedy) matters more here than anything else.

Captures

A capture is a persisted recording: the original audio, the raw transcript, and (optionally) an LLM-refined version. Captures appear in the Captures tab.

Create a capture

POST /api/voice/captures
Upload audio, run speech-to-text, and persist the result as a capture. Accepts multipart/form-data.
file
required
The audio file to store and transcribe. Must not be empty.
string
default:"file"
Where the audio came from (e.g. file, mic).
string
Spoken language code, or auto to detect. Falls back to the saved capture-settings language.
string
Transcription model — lipi, lipi-bharat or lipi-live. Falls back to the saved default.
string
transcribe or translate. Per-recording override of the saved default.
integer
Decoding beam size (1–5). Per-recording override.
string
Bias vocabulary for this recording. Per-recording override.

Response

Returns the created capture plus two settings flags the client uses to decide follow-up behavior.
string
Capture identifier.
string
Stored audio reference.
string
Origin of the audio.
string
Detected or supplied language (may be null).
integer
Audio length in milliseconds.
string
The raw speech-to-text output.
string
LLM-refined transcript, if refinement has run (else null).
string
Model size used for transcription.
string
Model used for refinement, if any.
object
The refinement toggles applied (smart_cleanup, self_correction, preserve_technical).
string
ISO-8601 creation timestamp.
boolean
Whether the workspace setting requests automatic refinement after capture.
boolean
Whether the workspace allows automatic paste of the transcript.

List captures

GET /api/voice/captures
Returns a paginated list of captures, newest first.
integer
default:"50"
Page size, between 1 and 200.
integer
default:"0"
Number of items to skip. Must be >= 0.

Response

array
Array of capture objects (see Create a capture).
integer
Total number of captures available.

Get a capture

GET /api/voice/captures/{capture_id}
Fetch a single capture by id.
string
required
The capture identifier.
Returns a capture object. Responds 404 if the capture does not exist.

Stream capture audio

GET /api/voice/captures/{capture_id}/audio
Streams the original recorded audio for a capture as audio/wav.
string
required
The capture identifier.
Returns the WAV file (Content-Type: audio/wav). Responds 404 if the capture or its audio file is missing.

Delete a capture

DELETE /api/voice/captures/{capture_id}
Permanently removes a capture.
string
required
The capture identifier.

Response

Responds 404 if the capture does not exist.

Refine a capture

POST /api/voice/captures/{capture_id}/refine
Runs the capture’s raw transcript through the LLM to clean it up. The refined text is saved to transcript_refined. Send a JSON body.
string
required
The capture identifier.
object
Refinement toggles. Omit to use the saved capture-settings defaults.
string
default:"BRAHMA-30B-FP8"
Refinement model. BRAHMA-30B-FP8 (BRAHMA-30B) is the only accepted value — the refinement model is pinned server-side. Falls back to the saved default.

Response

Returns the updated capture object with transcript_refined, llm_model, and refinement_flags populated. Responds 404 if the capture does not exist.

Retranscribe a capture

POST /api/voice/captures/{capture_id}/retranscribe
Re-runs speech-to-text on the capture’s stored audio — useful for retrying with a different language or a higher beam size. Send a JSON body.
string
required
The capture identifier.
string
Transcription model for the new pass — lipi, lipi-bharat or lipi-live; the legacy keys are accepted but resolve to lipi. Falls back to the saved default. Re-transcribing a capture with a different model is the point of this route.
string
Language code for the new pass. Falls back to the saved default.

Response

Returns the updated capture object with the new transcript_raw and stt_model. Responds 404 if the capture is missing, or 410 if its audio file is no longer available.

Capture readiness

GET /api/voice/capture/readiness
Reports whether the speech-to-text and refinement models selected in your capture settings are loaded and ready to serve on PeachDesk’s infrastructure. The Captures tab uses this to confirm dictation can start without waiting on a cold model.

Response

object
Readiness of the selected speech-to-text model.
object
Readiness of the selected refinement model, with the same fields as stt.
Models are hosted and served by PeachDesk. If a readiness check reports ready: false, the model is simply warming up server-side — retry shortly; you never need to download or manage model files yourself.