Skip to content

Server API

OpenASR can run a local HTTP server so existing applications can call local speech recognition through a single interface.

Start the local server:

bash
openasr serve

By default it binds 127.0.0.1:8080. Non-loopback remote serving requires --tls-self-signed (or another TLS setup) and pairing auth — see openasr serve --help.

Routes marked Operator require the admin/operator credential when pairing auth is active — paired remote-compute device tokens receive 403. In simple bearer-token mode the distinction does not apply; any valid key can call any route. /health and POST /v1/pairing/requests are always unauthenticated.

MethodPathOperator
GET/health
GET/v1/models
GET/v1/catalog
GET/v1/capabilities
GET/v1/devices
GET/v1/configYes
PUT/v1/configYes
POST/v1/audio/transcriptions
GET/v1/audio/transcriptions/progress
POST/v1/audio/transcriptions/{id}/cancel
POST/v1/audio/transcriptions/{id}/pause
POST/v1/audio/transcriptions/{id}/resume
POST/v1/audio/translations
ANY/v1/audio/realtime
GET/v1/historyYes
GET/v1/history/{id}Yes
DELETE/v1/history/{id}Yes
GET/v1/speakersYes
POST/v1/speakersYes
PATCH/v1/speakers/{id}Yes
DELETE/v1/speakers/{id}Yes
POST/v1/speakers/{id}/reenrollYes
GET/v1/models/local
POST/v1/models/local/importYes
GET/v1/models/default
POST/v1/models/defaultYes
PUT/v1/models/defaultYes
DELETE/v1/models/{id}Yes
POST/v1/models/{id}/pullYes
GET/v1/models/pull/{job_id}
GET/v1/models/pull/{job_id}/events
POST/v1/models/pull/{job_id}/cancelYes
POST/v1/models/pull/{job_id}/pauseYes
POST/v1/models/pull/{job_id}/resumeYes
POST/v1/pairing/requests
GET/v1/pairing/requestsYes
POST/v1/pairing/requests/{request_id}/approveYes
DELETE/v1/pairing/requests/{request_id}Yes
GET/v1/pairing/requests/{request_id}/credentialVaries
GET/v1/pairing/credentialsYes
DELETE/v1/pairing/credentials/{device_id}Yes

The server supports three auth modes:

  • Disabled (default) — loopback is trusted, no key required.
  • Bearer token — one or more static keys managed by openasr apikey create/list/revoke. Any valid key can call any route.
  • Pairing — an admin/operator token plus a device-credential registry. The operator-only column above applies in this mode: paired device tokens are rejected (403) on routes that touch the operator’s local data (config, history, speakers) or mutate models.

/health is always reachable without credentials, even when auth is enabled. On missing or invalid credentials the server returns 401 Unauthorized with a WWW-Authenticate: Bearer header. On valid but insufficient credentials for an operator-only route it returns 403 Forbidden.

bash
curl -s http://127.0.0.1:8080/v1/audio/transcriptions \
-F model=whisper-small \
-F response_format=json

Supported response_format values:

  • json
  • text
  • srt
  • vtt
  • verbose_json
  • markdown

This endpoint is compatible with the OpenAI audio transcriptions API subset; migrating an existing integration usually only requires pointing it at the local server URL and making sure the requested model is installed.

Long file transcriptions can be monitored and controlled while in flight:

  • GET /v1/audio/transcriptions/progress — returns the current phase and fraction-complete of the active file transcription. When nothing is running, all fields are zero/null.
  • POST /v1/audio/transcriptions/{id}/cancel — cancels at the next long-form slice boundary; already-decoded segments are discarded.
  • POST /v1/audio/transcriptions/{id}/pause — pauses at the next slice boundary; the request blocks until a matching resume or cancel.
  • POST /v1/audio/transcriptions/{id}/resume — resumes a paused job, keeping already-accumulated segments.

If a client disconnects mid-decode, the in-flight native worker is auto-cancelled rather than leaked.

POST /v1/audio/translations mirrors /v1/audio/transcriptions but always translates the source audio to English (matching the OpenAI translations contract), backed by a translation-capable pack such as Hy-MT2. It shares the same multipart form fields and non-streaming response formats.

/v1/audio/realtime upgrades to a WebSocket for streaming transcription and, when a translation-capable pack is installed, streaming translation. It emits incremental events (VAD, partial/final transcript segments, speech-boundary) instead of waiting for a full-file response.

  • GET /v1/catalog returns the signed model catalog (available models, quantizations, licenses) the server can pull from.
  • GET /v1/models/local lists model packs already installed under OPENASR_HOME, including an is_default flag per pack.
  • POST /v1/models/local/import installs a model pack from a .oasr file already present on local disk — it never touches the network.
  • GET /v1/models/default returns the current default pack selection.
  • POST /v1/models/default (or PUT) sets the default model by id or via an auto-select that picks the best installed quant; persists across restarts.
  • DELETE /v1/models/{id} removes an installed pack. If it was the default, the default-model selection is cleared.

POST /v1/models/{id}/pull starts an async download job. The JSON body accepts quant, size, accept_license, and from. License-gated models require accept_license: true or the request returns 400. If the pack is already installed the response is 200; otherwise 202 Accepted with a queued job snapshot.

  • GET /v1/models/pull/{job_id} — job status snapshot (state, progress bytes, speed, ETA, error, installed path).
  • GET /v1/models/pull/{job_id}/events — Server-Sent Events stream of download progress.
  • POST .../cancel, .../pause, .../resume — lifecycle control (operator-only).
  • GET /v1/config — returns the full config document (config and preferences). Operator-only.
  • PUT /v1/config — accepts either a full config-document JSON body or a narrow preferences patch (e.g. {"preferences": {"diarize": true}}) that merges over the existing stored preferences without resetting other fields. Validated against the model registry before saving. Operator-only.

See the Configuration page for available preference keys.

  • GET /v1/history — paginated list of past transcription/translation runs. Query parameters: search, kind (file or live), limit (default 50, max 500), offset. Returns {object, data, total, limit, offset}.
  • GET /v1/history/{id} — single entry detail; 404 if not found.
  • DELETE /v1/history/{id} — delete one entry; returns {deleted, id}.

All history endpoints are operator-only. Entries are pruned according to the history_retention preference on every request.

GET /v1/speakers, POST /v1/speakers, PATCH /v1/speakers/{id}, DELETE /v1/speakers/{id}, and POST /v1/speakers/{id}/reenroll manage enrolled speaker profiles used for diarization and speaker labeling. All are operator-only. See the Diarization page for details on speaker enrollment.

  • GET /v1/capabilities — returns what the currently bound model/backend supports (transcription, realtime), derived from the native pack’s capabilities.
  • GET /v1/devices — read-only hardware/compute-device enumeration (default_execution_target, devices), reflecting the daemon’s actual ggml runtime detection.

Pairing lets a remote-compute device authenticate to the server with its own credential, distinct from the operator’s admin token.

  • POST /v1/pairing/requests — a remote device creates a pairing request (unauthenticated entry point).
  • GET /v1/pairing/requests — operator lists pending requests.
  • POST /v1/pairing/requests/{request_id}/approve — operator approves, issuing a device credential.
  • DELETE /v1/pairing/requests/{request_id} — operator rejects a request.
  • GET /v1/pairing/requests/{request_id}/credential — fetch the issued credential for an approved request.
  • GET /v1/pairing/credentials — operator lists all issued credentials.
  • DELETE /v1/pairing/credentials/{device_id} — operator revokes a device.

A paired device identifies itself with the x-openasr-remote-compute: client request header. Operator-only routes reject device tokens with 403.

bash
curl -s http://127.0.0.1:8080/health

Besides status, server_version, pid, and instance_token, the response carries fields useful for diagnosing model residency and idle behavior:

  • model_installed (bool) — whether a model is currently bound and ready to serve transcription requests. false on a fresh install with zero pulled models; the daemon is still healthy, it just has nothing to transcribe with yet.
  • model_resident (bool) — whether the bound model’s runtime is currently resident in memory, i.e. ready to transcribe instantly with no cold-load latency. model_installed: true, model_resident: false means a model is bound but its runtime has been unloaded (idle past the configured idle_unload threshold, or never loaded yet this boot) — the next transcription request pays a cold rebuild before it can run, which is expected, not an error. Always false when model_installed is false.
  • native_active_count (u64) — the process-wide count of currently active native requests/sessions: in-flight offline transcriptions/translations and attached realtime native-streaming sessions both count. A transient nonzero count during a single request is normal; useful when diagnosing why idle_unload has not fired yet.
  • idle_seconds (u64) — seconds elapsed since the native activity count last returned to zero (0 while native_active_count is nonzero). Compare against the configured idle_unload threshold to see how close the next eviction sweep is.
  • abandoned_worker_count (u64) — the count of native streaming decode workers the decode watchdog has abandoned because a decode never returned within its budget. Normally 0; a nonzero value is a strong signal of a GPU/driver-level decode hang. The daemon fails loud and exits once this reaches its internal threshold, so a supervisor can restart it cleanly.

To keep memory free, the server evicts an idle model’s runtime from memory after a configurable idle period (idle_unload) — the pack stays installed on disk, so the next request just pays a normal load/warm-up cost again. The default threshold is 10 minutes of no active request or realtime session; other supported settings are never, now (~5 seconds), 2m, and 1h.

The server runs native (the same fail-closed, ggml-backed backend as the CLI) against an already-installed or explicitly pinned (--model-pack) local pack. It never downloads a model to satisfy a transcription request — the operator-authenticated POST /v1/models/{id}/pull is the only server-side path that downloads from the network; local imports via /v1/models/local/import install from a path already on disk. There is no telemetry.

See the Models page for available models and the CLI reference for install/management commands. To run this server from a published container image (CPU multi-arch or CUDA), see Docker.