Skip to content

Advanced API

Who this is for: developers integrating with the speech service.

The speech service (caption-local) exposes a small HTTP API. It is built for a local, trusted producer: by default there is no CORS allowance, no multi-tenant isolation and no permanent store. This page is a concise reference; the upstream API.md carries the full contract.

When CAPTION_API_KEY is set, every actual API request must carry the service access token as a Bearer header. Preflight OPTIONS requests do not require it.

Service access token

Send Authorization: Bearer <token>, where <token> is the configured CAPTION_API_KEY. See Concepts in plain words.

Endpoints at a glance

Method Path What it does
GET /v1/models Returns the one loaded local model.
POST /v1/audio/transcriptions OpenAI-style transcription of an uploaded WAV.
POST /v1/audio/translations OpenAI-style speech-to-English translation.
POST /transcribe Native PCM endpoint for rolling live capture.
GET /health Service status, available after model load and warmup.
DELETE /streams/{stream_id} Close an idle stream session and forget its cached results.

OpenAI-style WAV API

A limited subset of the OpenAI transcription and translation request contracts:

  • GET /v1/models returns the single loaded local model.
  • POST /v1/audio/transcriptions takes multipart fields file, model, and optional language and response_format (json or text). JSON responses contain text. Language detection is automatic by default.
  • POST /v1/audio/translations is the same except it has no language field; it detects the speech language and translates to English.

Use the loaded local model name, or whisper-1 as an explicit compatibility alias for it. This does not load OpenAI's hosted model or switch models per request. Only uncompressed PCM WAV, mono or stereo, 8–48 kHz, 0.01–12 seconds, within a 5 MiB multipart envelope is supported. Convert or chunk other audio first. The adapter retains native detail errors and HTTP status codes.

This example uses the official OpenAI Python SDK, targeting only the local server.

from openai import OpenAI
import os
client = OpenAI(base_url="http://127.0.0.1:8765/v1",
                api_key=os.environ.get("CAPTION_API_KEY") or "local-unused")
with open("speech.wav", "rb") as audio:
    result = client.audio.transcriptions.create(
        model="small", file=audio, language="fr")
print(result.text)

Health

GET /health is available only after the model has loaded and the decoder has actually warmed up. It reports readiness together with details such as the model, device, compute type, sample rate, supported languages, modes, busy, completed and failed. It also reports scheduler figures including max_streams, workers, sessions, running, pending, queue settings and counters such as rejected and queue_timeouts.

Native transcribe

POST /transcribe?language=es&mode=both

Required headers are Content-Type: application/octet-stream and X-Caption-Local: 1, with optional X-Stream-ID and X-Request-ID (8–80 ASCII letters, numbers, _ or -). The body is little-endian float32 mono PCM at 16 kHz, normalized to [-1, 1], 0.01–12 seconds, with no WAV header.

language defaults to en and accepts Whisper language codes or auto. mode is transcribe (default), translate (English only) or both. A JSON response includes text, transcript, translation, language, mode, timing values and the request and stream IDs. Unrequested output fields are empty strings.

Rolling windows add window=1, final=0 and context_seconds=0.5 to decode an unfinished window; final=1 (the default) commits the complete supplied window.

Streams and errors

One request may upload, queue or run per stream, and independent streams share FIFO worker admission. Successful results are kept in memory for up to 120 seconds. DELETE /streams/{stream_id} with the X-Caption-Local: 1 header closes an idle session immediately; a busy session returns 409.

Common status codes:

Status Meaning
400 Invalid audio, language, mode, context or ID.
401 Missing or incorrect service access token.
403 Wrong or missing local header, or a foreign Origin.
408 Upload exceeded the ten-second limit.
409 A reused ID with different input.
413 / 415 Oversized audio / wrong content type.
429 Stream busy, capacity reached, or queue deadline exceeded.
500 Inference failed.
503 HTTP concurrency limit or restarting service.

Related pages: Configuration, Relay and rooms and the Glossary.