Realtime API
Realtime medical transcription
Receive a fast draft, confirmed utterances and a closing session record, with optional speaker activity.
Regions & endpoints
wss://api.us.omi.health/v1/stream; for EU-only, wss://api.eu.omi.health/v1/stream. api.omi.health routes each new connection to the nearest healthy EU or US region. Open sessions do not move between regions; if a connection drops, open a new one and it goes to a healthy region. Regions & endpointsAvailable on every plan
Understand the event tiers
Draft text appears quickly and may change. Every preview carries aturn_id, a strictly increasing sequence, and a revision identifier. Replace the previous preview for that turn; never append revisions as duplicate text. A confirmed event closes one utterance and is immutable. The closing final event assembles the complete authoritative record. It is not a separate batch re-decode.
Speaker activity is separate from transcript wording: it may revise provisional labels, but it cannot rewrite confirmed or final text. If optional speaker processing is unavailable, transcription continues without silently dropping audio.
Connect
Connect to wss://api.omi.health/v1/stream and send the API key in the first start message. Browsers cannot set a custom Authorization header during the WebSocket upgrade. Send binary PCM16 audio at 16 kHz mono after the server returnsready, then send {"type":"stop"}.
{
"type": "start",
"api_key": "$OMI_API_KEY",
"session_id": "your-unique-id",
"model": "omi-medical-1",
"streaming_mode": "realtime",
"event_schema": "omi-agent-v1",
"audio_format": "pcm_s16le",
"sample_rate_hz": 16000,
"channels": 1,
"language": "en",
"diarization": {"enabled": false}
}Set model to omi-medical-1 or omi-general-1. Before sending audio, verify ready.model.served matches your requested model. The ready.max_session_s field states the session limit; the general batch 60-second audio boundary does not apply to this WebSocket.
Vocabulary is a batch feature
omi-medical-1 for vocabulary on/off tests. Adding a batch vocabulary field to the start message does not demonstrate that it was applied.Turn and connection controls
When your application knows the speaker has finished, send{"type":"finalize","id":"end-1"} to close the current turn without ending the session. The server returnsfinalize_ack with the same id. Use stop to end the session and receive its record. An explicit end signal is different from measuring automatic speech-end detection.
{"type":"finalize","id":"end-1"}
{"type":"keep_alive","id":"ping-1"}
{"type":"update_configuration","endpointing":{"silence_ms":400}}keep_alive returns keep_alive_ack. Configuration changes return configuration_updated. You may set endpointing.silence_ms at start or mid-session between 200 and 1100 ms. The ready event reports the active controls and endpointing window. Omit mode for standard operation;mode=min_latency trades accuracy for faster automatic turn closure and does not promise a 240 ms response.
Transcript events
{
"type": "partial",
"tier": "draft",
"turn_id": "turn-3",
"sequence": 18,
"revision_id": "session-123:draft:r4",
"replaces_revision_id": "session-123:draft:r3",
"text": "Have you taken any pain…",
"mutable": true,
"provisional": true,
"medical_record": false
}{
"type": "turn_final",
"turn_id": "turn-3",
"sequence": 19,
"revision_id": "session-123:turn:r3",
"start_s": 12.4,
"end_s": 15.8,
"text": "Have you taken any painkillers?",
"mutable": false,
"authoritative": true,
"can_authorize_response": true,
"medical_record": false
}partialevents are mutable previews. Key them byturn_id, ignore stale revisions, and replace the prior preview named byreplaces_revision_id.turn_end_candidateis only a visual hint. Ifturn_continuationfollows, cancel work based on that candidate.turn_finalcarries immutable turn text and is the only realtime text event that may authorize an agent response.- With
omi-agent-v1, the closingcanonical_recordevent containsfinal_transcriptand record metadata. The legacy schema calls this eventfinal. Keep it separate from your concatenated confirmed turns. - Every non-final event carries
medical_record=false. Never promote a draft or a failed window silently. - For word timestamps and canonical speaker labels, upload the complete recording through the batch API.
Optional live speakers
Send "diarization":{"enabled":true} in the start message to request speaker activity. It is off by default and does no speaker work when omitted. speaker_update events are provisional, can revise a short recent tail, and never change transcript text. A client may display a whole confirmed utterance under the speaker with the strongest overlapping activity, but must keep the preview label revisable. Use batch diarization for the canonical speaker transcript.
Capacity and retries
Realtime sessions and live speaker labels are admitted from separate, bounded pools; live-speaker capacity is the smaller of the two. Builder projects can run 2 live sessions including 1 speaker room; Pay as you go projects can run 10 including 2 speaker rooms. When a pool is full, additional starts are rejected before audio with WebSocket close code1013: TOO_MANY_STREAMS means text capacity is full; SPEAKER_CAPACITY_FULL means text is available but the optional live-speaker pool is full. Reconnect without diarization or retry with exponential backoff and jitter. Limits are aggregated per project, not multiplied by API keys. Enterprise can contract for custom maximums and reserved capacity.
Pricing
/v1/stream audio and optional speaker labels use the project's pooled monthly allowance. After the included 25 hours, Pay as you go usage is $0.45 per audio-hour, measured from audio sent during the session. An active session is never cut off at the billing boundary; a blocked Builder reconnect receivesbilling_blocked before audio is accepted.