API reference · Voice sessions
Voice sessions
A session is the server-owned unit of model selection, realtime attachment, wallet reservation, usage measurement, and settlement.
Endpoints
All session operations are scoped to the key that created the session.
Create a voice session
Reserve a bounded wallet amount and create a server-owned speech-to-speech session.
/v1/voice/sessionsBearer VR_SKHeaders
| Field | Type | Description |
|---|---|---|
Authorizationrequired | string | VoiceOpenRouter secret key. Keep it on your server and never put it in a URL. |
Content-Typerequired | stringapplication/json | The request body is JSON. |
Idempotency-Key | string | Optional printable key. Repeating the same owner and request returns the same session. |
Request body
application/jsonSelect one model from GET /v1/models. The only supported public mode is speech_to_speech.
| Field | Type | Description |
|---|---|---|
modelrequired | string | Catalog model id returned by GET /v1/models. |
moderequired | stringspeech_to_speech | Enables the public realtime speech-to-speech contract. |
{
"model": "xai/grok-voice-latest",
"mode": "speech_to_speech"
}Response
201 CreatedThe session is ready to attach through the gateway-owned realtime URL.
| Field | Type | Description |
|---|---|---|
idrequired | string | Opaque VoiceOpenRouter session identifier. |
statusrequired | stringready | active | completed | cancelled | failed | expired | Current server-owned lifecycle status. |
modelrequired | string | The catalog model id selected at session creation. |
moderequired | stringspeech_to_speech | The public session mode for this contract. |
realtimerequired | object | Gateway-owned WebSocket URL and protocol name. |
audiorequired | object | Negotiated public input and output audio formats. |
capabilitiesrequired | object | Capabilities available for the selected catalog model. |
billingrequired | object | Preauthorization and remaining wallet information. |
usagerequired | object | Server-measured usage and the rate snapshot used for settlement. |
trace_idrequired | string | Redacted support lookup identifier; never a provider credential. |
{
"id": "vs_EXAMPLE",
"object": "voice.session",
"status": "ready",
"model": "xai/grok-voice-latest",
"mode": "speech_to_speech",
"realtime": {
"url": "wss://api.voiceopenrouter.com/v1/realtime?session_id=vs_EXAMPLE",
"protocol": "vor-realtime-v1"
},
"audio": {
"input": {
"type": "audio/pcm",
"encoding": "pcm16le",
"sample_rate_hz": 24000,
"channels": 1
},
"output": {
"type": "audio/pcm",
"encoding": "pcm16le",
"sample_rate_hz": 24000,
"channels": 1
}
},
"capabilities": {
"speech_to_speech": true,
"server_vad": true,
"barge_in": true,
"input_transcription": "optional",
"output_transcription": "optional"
},
"created_at": 1770000000,
"expires_at": 1770000900,
"billing": {
"preauthorized_cents": 50,
"balance_cents": 950,
"reserved_cents": 50
},
"usage": {
"model": "xai/grok-voice-latest",
"provider": "xai",
"pricing_source": "upstream_derived",
"rate_snapshot_id": "rate_EXAMPLE",
"audio_in_ms": 0,
"audio_out_ms": 0,
"billed_cents": 0
},
"trace_id": "trace_EXAMPLE"
}Responses
status codes201Session created and preauthorized.401The key is invalid, revoked, or does not own the resource.invalid_vr_sk402The wallet cannot cover the session preauthorization.insufficient_wallet_balance404The selected model is not available to this key.model_not_found409An idempotency key was reused with a different request.idempotency_conflict- The selected model rate is snapshotted at session creation. Settlement uses server/provider usage, not client-reported cost.
- The realtime URL and protocol are gateway-owned public contract values; provider endpoints and keys are never returned.
Retrieve a voice session
Read the current lifecycle state and server-measured usage for an owned session.
/v1/voice/sessions/{session_id}Bearer VR_SK used to create the sessionPath parameters
| Field | Type | Description |
|---|---|---|
session_idrequired | string | The id returned by POST /v1/voice/sessions. |
Response
200 OKThe owned session resource, including current usage and billing state.
| Field | Type | Description |
|---|---|---|
idrequired | string | Opaque VoiceOpenRouter session identifier. |
statusrequired | stringready | active | completed | cancelled | failed | expired | Current server-owned lifecycle status. |
modelrequired | string | The catalog model id selected at session creation. |
moderequired | stringspeech_to_speech | The public session mode for this contract. |
realtimerequired | object | Gateway-owned WebSocket URL and protocol name. |
audiorequired | object | Negotiated public input and output audio formats. |
capabilitiesrequired | object | Capabilities available for the selected catalog model. |
billingrequired | object | Preauthorization and remaining wallet information. |
usagerequired | object | Server-measured usage and the rate snapshot used for settlement. |
trace_idrequired | string | Redacted support lookup identifier; never a provider credential. |
{
"id": "vs_EXAMPLE",
"object": "voice.session",
"status": "ready",
"model": "xai/grok-voice-latest",
"mode": "speech_to_speech",
"realtime": {
"url": "wss://api.voiceopenrouter.com/v1/realtime?session_id=vs_EXAMPLE",
"protocol": "vor-realtime-v1"
},
"audio": {
"input": {
"type": "audio/pcm",
"encoding": "pcm16le",
"sample_rate_hz": 24000,
"channels": 1
},
"output": {
"type": "audio/pcm",
"encoding": "pcm16le",
"sample_rate_hz": 24000,
"channels": 1
}
},
"capabilities": {
"speech_to_speech": true,
"server_vad": true,
"barge_in": true,
"input_transcription": "optional",
"output_transcription": "optional"
},
"created_at": 1770000000,
"expires_at": 1770000900,
"billing": {
"preauthorized_cents": 50,
"balance_cents": 950,
"reserved_cents": 50
},
"usage": {
"model": "xai/grok-voice-latest",
"provider": "xai",
"pricing_source": "upstream_derived",
"rate_snapshot_id": "rate_EXAMPLE",
"audio_in_ms": 0,
"audio_out_ms": 0,
"billed_cents": 0
},
"trace_id": "trace_EXAMPLE"
}Responses
status codes200Session returned.401The key is invalid or does not own the session.invalid_vr_sk404No session exists for this owner and id.session_not_found410The session has expired and is no longer attachable.session_expired- A read may expire and settle an idle session as part of the server lifecycle.
- Session ownership is checked before any usage or billing fields are returned.
End a voice session
Close the session and settle from accepted server/provider usage.
/v1/voice/sessions/{session_id}/endBearer VR_SK used to create the sessionPath parameters
| Field | Type | Description |
|---|---|---|
session_idrequired | string | The id returned by POST /v1/voice/sessions. |
Request body
application/jsonThe body is optional. Only a bounded close reason is accepted.
| Field | Type | Description |
|---|---|---|
reason | stringclient_closed | timeout | error | Optional bounded reason for closing the session. |
{
"reason": "client_closed"
}Response
200 OKThe terminal session resource. Repeating the request does not duplicate settlement.
| Field | Type | Description |
|---|---|---|
idrequired | string | Opaque VoiceOpenRouter session identifier. |
statusrequired | stringready | active | completed | cancelled | failed | expired | Current server-owned lifecycle status. |
modelrequired | string | The catalog model id selected at session creation. |
moderequired | stringspeech_to_speech | The public session mode for this contract. |
realtimerequired | object | Gateway-owned WebSocket URL and protocol name. |
audiorequired | object | Negotiated public input and output audio formats. |
capabilitiesrequired | object | Capabilities available for the selected catalog model. |
billingrequired | object | Preauthorization and remaining wallet information. |
usagerequired | object | Server-measured usage and the rate snapshot used for settlement. |
trace_idrequired | string | Redacted support lookup identifier; never a provider credential. |
{
"id": "vs_EXAMPLE",
"object": "voice.session",
"status": "ready",
"model": "xai/grok-voice-latest",
"mode": "speech_to_speech",
"realtime": {
"url": "wss://api.voiceopenrouter.com/v1/realtime?session_id=vs_EXAMPLE",
"protocol": "vor-realtime-v1"
},
"audio": {
"input": {
"type": "audio/pcm",
"encoding": "pcm16le",
"sample_rate_hz": 24000,
"channels": 1
},
"output": {
"type": "audio/pcm",
"encoding": "pcm16le",
"sample_rate_hz": 24000,
"channels": 1
}
},
"capabilities": {
"speech_to_speech": true,
"server_vad": true,
"barge_in": true,
"input_transcription": "optional",
"output_transcription": "optional"
},
"created_at": 1770000000,
"expires_at": 1770000900,
"billing": {
"preauthorized_cents": 50,
"balance_cents": 950,
"reserved_cents": 50
},
"usage": {
"model": "xai/grok-voice-latest",
"provider": "xai",
"pricing_source": "upstream_derived",
"rate_snapshot_id": "rate_EXAMPLE",
"audio_in_ms": 0,
"audio_out_ms": 0,
"billed_cents": 0
},
"trace_id": "trace_EXAMPLE"
}Responses
status codes200Session closed; repeated calls are idempotent.400The close body is malformed or contains an unsupported field.invalid_request401The key is invalid or does not own the session.invalid_vr_sk404No session exists for this owner and id.session_not_found409Settlement could not complete consistently.session_termination_failed503The session store is unavailable.session_store_unavailable- Client-reported usage_cents, elapsed time, and token counts are not accepted by this endpoint.
- The terminal decision comes from the server/worker response lifecycle; a short silence is not by itself completion.
Lifecycle notes
The gateway owns terminal state and billing decisions.
- New sessions start in
ready; they may transition toactiveafter realtime input begins. - Terminal statuses are
completed,cancelled,failed, andexpired. - Repeated end requests return the existing terminal resource and do not duplicate wallet settlement.
- Use the returned realtime URL; do not construct a provider connection directly.