Overview
The Voxray server exposes a JSON/HTTP REST API for health, WebRTC signaling, session management, and Prometheus metrics, plus WebSocket and telephony transports for real-time voice pipelines. All JSON endpoints follow a consistent success and error envelope. The interactive OpenAPI specification is available at/swagger/ when the server is running. The spec file (swagger.json) is located in the docs/ folder; Mintlify renders it automatically when configured in mint.json.
Base URL
The default bind address islocalhost on port 3042. Override both with configuration or environment variables.
When
tls_enable is true, the server calls ListenAndServeTLS and the base URL becomes https://.
Versioned paths
All core routes are available at both a versioned prefix and a legacy path:
Prefer the versioned paths for all new integrations. Legacy paths remain supported but are not guaranteed in future major versions.
Authentication
Authentication is optional and controlled entirely by theserver_api_key configuration value (or the VOXRAY_SERVER_API_KEY environment variable). When this key is not set, all endpoints are open.
When a key is configured, protected endpoints require one of the following request headers:
401 Unauthorized with error code UNAUTHORIZED.
Protected vs open endpoints
The
/daily-dialin-webhook endpoint uses a separate secret (daily_dialin_webhook_secret / VOXRAY_DAILY_DIALIN_WEBHOOK_SECRET) validated via the X-Webhook-Secret header, not the server API key.Request and Response Format
All JSON endpoints consume and produceapplication/json. Clients may send X-Request-ID; the server echoes it in response meta.requestId.
Body size limit: Request bodies are capped at max_request_body_bytes (default 256 KB). Configure via VOXRAY_MAX_BODY_BYTES.
Success envelope
body.data. The meta object is present on all successful responses.
Error envelope
details is included only for validation errors and contains per-field information.
HTTP status codes
All error codes
Endpoints Overview
* When
server_api_key is configured. † Uses X-Webhook-Secret when daily_dialin_webhook_secret is set.
Endpoint Details
GET /health
Liveness probe. Returns 200 when the server process is running regardless of dependency state.GET /ready
Readiness probe. Whensession_store is redis, pings Redis before responding. Use this endpoint for load balancer readiness checks.
GET /metrics
Returns Prometheus metrics in text exposition format. Whenmetrics_enabled is false, returns 204 No Content.
GET /swagger/
Serves the Swagger UI. The OpenAPI definition file isdocs/swagger.json. Append doc.json for the raw spec: GET /swagger/doc.json.
POST /webrtc/offer
Submit a WebRTC SDP offer. The server returns an SDP answer and wires the new transport into the voice pipeline. Available whentransport is smallwebrtc or both.
Request body:
Example:
POST /start
Create a runner session. Returns asessionId plus optional ICE config or Daily room details. Supports idempotency via the Idempotency-Key header.
Headers:
Request body:
Example:
createDailyRoom is true, data also contains dailyRoom (room URL) and dailyToken.
POST /sessions//api/offer
Submit a WebRTC SDP offer for an existing session. Theid path parameter must be a valid UUID obtained from POST /start.
Path parameters:
Request body:
Example:
PATCH /sessions//api/offer
ICE trickle acknowledgment. Fire-and-forget — returns 204 with no body.204 No Content on success. Same 400/401/404 errors as POST apply.
GET /ws
WebSocket upgrade for the real-time voice pipeline. One connection equals one session. The API key check (when configured) is performed before the protocol upgrade — a 401 JSON response is returned if it fails. Query parameters:
Browser example:
POST / (Telephony webhook)
Accepts webhook callbacks from Twilio, Telnyx, Plivo, and Exotel whenrunner_transport is set to one of those providers. Response format depends on the provider.
- Twilio / Telnyx / Plivo
- Exotel
Returns
200 OK with Content-Type: application/xml:GET /telephony/ws
WebSocket endpoint for telephony media streams. The provider is detected automatically from the first frames received. Available whenrunner_transport is twilio, telnyx, plivo, or exotel. No authentication required.
POST /daily-dialin-webhook
Handles incoming Daily PSTN dial-in events. Available whenrunner_transport=daily and dialin=true.
When daily_dialin_webhook_secret is set, the request must include X-Webhook-Secret: <secret>.
Request body:
Success (201, non-test):
Middleware
Middleware is applied in the following order for every request:
Auth is enforced per-handler via
requireAPIKey, not as global middleware.
Idempotency
POST /start supports the Idempotency-Key request header. Submitting the same key within 24 hours returns the cached 201 Created response body without creating a new session. The cache is in-memory and does not survive process restarts.
Interactive API Docs
The full interactive Swagger UI is served at/swagger/ when the server is running. The raw OpenAPI 2.0 spec is at /swagger/doc.json and is also available as docs/swagger.json in the repository.