Skip to content

Message reference

Client → server

start

Sent once, straight after the socket opens and before any audio. On reconnect, send it again with encounter_id set.

{
  "object": "start",
  "prompt_id": "33907f11-7792-4b63-be9b-d0a3b6dc074c",
  "consultation_name": "Follow-up: hypertension",
  "show_transcript": true,
  "encounter_id": null,
  "ext_patient_id": "MRN-884213",
  "visit_id": "VISIT-2211045",
  "ext_user_id": "DR-10293"
}
Field Type Required Description
object string Yes "start"
prompt_id string (UUID) Yes Note template. Issued by Sahl AI for your organization.
consultation_name string Recommended Human-readable label for the encounter.
show_transcript boolean Optional Send live transcript_item messages. Default false. Requires the transcript feature on your account.
encounter_id string | null On reconnect null for a new consultation. On reconnect, send the encounter_id you received to resume it instead of creating a duplicate.
ext_patient_id string Recommended Your patient identifier (MRN).
visit_id string Recommended Your encounter or visit identifier.
ext_user_id string Optional Your clinician identifier.

audio_chunk

{ "object": "audio_chunk", "payload": "M/8x/y3/K/8v/zf/…", "seq_id": 1 }
Field Type Description
payload string Base64 PCM-16, 16 kHz mono. See Audio format.
seq_id integer Starts at 1 and increases by one per chunk. Never reset it, not even across reconnects within the same consultation.

pause

{ "object": "pause", "seq_id": 430 }

Stop sending audio after this, but keep the socket open and keep sending ping. To resume, send audio_chunk messages again, continuing the same seq_id sequence. There is no resume message. Do not send start again on the same socket.

end_transcript

{ "object": "end_transcript", "seq_id": 842 }

Sent once, after the final audio chunk, with the next seq_id. The server finishes transcribing, acknowledges outstanding chunks, generates the note and sends task_status. Keep the socket open until task_status arrives. Closing early abandons delivery of the note.

ping

{ "object": "ping" }

Send every 30 seconds for the whole life of the socket, including while paused and while you wait for the note. Idle connections are dropped after 100 seconds, and note generation can take longer than that.

Server → client

encounter_created

{ "object": "encounter_created", "encounter_id": "6b0d5c39-1f2a-4e77-b0aa-2c9d4e81f5b3" }

Sent once, shortly after start. Store it. It identifies the consultation and is required to resume after a reconnect.

ack

{ "object": "ack", "seq_id": 1 }

Confirms the server received the chunk with that seq_id. Remove it from your resend buffer. Acks can arrive out of order relative to transcripts.

transcript_item

{
  "object": "transcript_item",
  "id": "c1d6b1e4-…",
  "text": "Have you had any chest pain since we last spoke?",
  "start_offset_ms": 12400,
  "end_offset_ms": 15980,
  "timestamp": "2026-11-01T09:14:32.104Z"
}

One message per finalised speech segment, sent only when show_transcript is true. Offsets are milliseconds from the start of the consultation, and they continue across resumes.

task_status

The final message. The server closes the socket after sending it.

{
  "object": "task_status",
  "status": "SUCCESS",
  "summary": [
    { "title": "Chief Complaint", "body": ["Intermittent chest tightness for two weeks."], "edited_body": null, "show": true },
    { "title": "Assessment and Plan", "body": ["Stable angina suspected; ECG and troponin ordered."], "edited_body": null, "show": true }
  ],
  "errorMsg": ""
}
{
  "object": "task_status",
  "status": "FAILED",
  "summary": [],
  "errorMsg": "Failed to generate summary"
}
Field Type Description
status "SUCCESS" | "FAILED" Outcome.
summary array Ordered note sections (title, body[], edited_body, show). Your prompt_id defines the sections. Empty on failure.
errorMsg string Reason for the failure. Empty on success.

On failure the transcript is still saved against the encounter_id. Contact Sahl AI support if the note needs to be regenerated.

warning_message

{ "object": "warning_message", "code": "1007", "message": "No speech detected in segment." }

Not fatal. Keep streaming. You can show it to the clinician, for example as a microphone check.

Code Meaning
1007 A segment contained no speech. Check that the microphone is not muted.
INVALID_NOTE_CONFIG An optional note configuration in start was invalid and has been ignored.

error

{ "object": "error", "code": "UNKNOWN_MESSAGE_TYPE", "message": "Unknown message type: resume" }
Code Meaning
INVALID_MESSAGE The frame was not valid JSON or had no object field.
UNKNOWN_MESSAGE_TYPE The object value is not recognised.
PROCESSING_ERROR The server could not process the message. Report the encounter_id to support.
TRANSCRIPTIONS_ERROR Transcription failed while finishing the consultation.

pong

{ "object": "pong" }

Reply to ping. Use it only to reset your liveness timer.