A session is one realtime conversation. A browser socket, a phone leg, a native client, one half of a duet and a live interpretation are all the same kind of row, so tooling written against one works against all of them.
source is whichever surface opened the session — phone for a carrier leg, and whatever a client passed on the query string otherwise (live, duet, reader, ios, api). paired_session_id is the other half of a duet, so both halves can be replayed together. The list omits transcripts on purpose. GET /v1/speech/sessions/{session_id} returns the same object with transcript included.

The transcript

Turns in arrival order, each { "role", "text", "at" }at being seconds from the start of the session, so a transcript lines up with the recording without a second clock:
ttfb_ms on an assistant turn is end-of-user-speech to first audio out — the number a caller actually feels. median_reply_ms on the session summary is the median of those. Watch the tail rather than the mean: it is the slow turns that make people talk over the model. An interrupted turn was cut short by barge-in, and its text is trimmed to what the caller actually heard rather than what the model had generated. Without that trim, a transcript claims things were said that nobody heard.
Transcripts for /v1/realtime sessions exist only where the deployment sets SPEECH_SESSION_RECORDING. Phone legs are the exception: their transcript is always kept, because for a Care call the transcript is the visit and the post-call analysis reads it. The same environment variable still gates whether audio is uploaded.

Recordings

Audio is stored per direction, not mixed. The realtime protocol carries the two sides separately, so keeping them separate means you know who said what with no diarization step at all. Each download mints a fresh signed URL rather than proxying bytes through the API, which is why the storage bucket needs no anonymous access:
Ask for a track the session does not have and the 404 lists the ones it does. recording_truncated on the summary means the session ran past the recorder’s ceiling and the audio stops before the transcript does.

Erasing one

A real delete, not a flag: the audio objects go first, then the transcript and the row. A recording is a person’s voice and a transcript is what they said, so “deleted” has to mean the bytes are gone. A track that fails to erase leaves the row in place so the delete can be retried rather than half-succeeding in silence. The organization-wide retention sweep runs through exactly this path. See Compliance for the retention schedule and what is configurable.

Access

These are org-scoped reads: only the organization that owns a session can see it. session_uuid appears in storage keys, so possession of a uuid must not on its own grant access — an API key or a signed-in session is required for every call above.

Going further

Realtime

The protocol these sessions record.

Latency

What ttfb_ms is made of, and which knobs move it.

Architecture

Where a session runs, and what else the platform is made of.

Compliance

Consent, disclosure and retention.