Recording retrieval is API-only today — the terminal has no built-in player yet. The endpoints below
are live and covered by service tests. Browser playback and seeking work through the gateway: a
Range
request returns a 206 Partial Content with its Content-Range and Accept-Ranges headers intact.
See the capability truth table.make all prints a key when the stack comes up.
To record a meeting without transcribing it and take the audio away for your own
speech-to-text, see Capture now, transcribe later.
List recordings
Get the playable audio
Resolve the master metadata (finalize-on-read), which points at the raw byte stream:raw_url of the form
GET /recordings/{recording_id}/media/{media_file_id}/raw — the actual audio bytes the player loads:
Range requests (playback and seek)
The/raw endpoint honours HTTP Range — a partial request returns 206 Partial Content carrying
Content-Range and Accept-Ranges: bytes, preserved through the gateway front door. This is what
lets a browser <audio>/<video> element stream and seek the recording instead of aborting the fetch:
Where it’s stored
meeting-api writes recordings over S3 to the bucket configured byMINIO_*
(Configuration); clients only ever receive the bytes through the
API above. On a self-host that’s infrastructure you control; a no-egress deployment keeps recordings
entirely in-VPC.
Lite and Compose run that S3 store themselves: versitygw, whose POSIX backend keeps each object as a
plain file. The volume holds the bucket as a directory:
Each recording directory holds the uploaded chunks (
000000.wav, 000001.wav, …) and, once the
recording has been read or finalized, the assembled master.wav. The content type and ETag of each
object are stored in the file’s extended attributes (user.*), not in the file.
Backups
Back up the storage volume together with Postgres: the recordings list comes from Postgres, the audio from the volume, and a recording plays only when both are restored. Copy the volume with a tool that keeps extended attributes —rsync -aX or cp -a — onto a
filesystem that supports them (ext4 and XFS do; FAT, exFAT and many network shares do not). Stop the
storage container first so no upload is caught half-written:
vexa-lite-storage with docker stop, copy volume vexa-lite-storagedata the same
way, then docker start vexa-lite-storage. To restore, stop the storage container, copy back into
the empty volume with rsync -aX, and start it again.
A copy that drops the attributes (plain cp -r) still plays back through Vexa, which sets the audio
content type from the recording’s format, but an S3 client reading the store directly then gets a
generic content type instead of audio/wav, and no ETag, for those objects.
Delete a recording
409 while the meeting
is still in flight). A storage error leaves the metadata intact so you can safely retry. To erase a
completed meeting’s transcript and every recording together, use
DELETE /meetings/{meeting_id}.
Deletion does not promise immediate removal from database snapshots, object-store version history,
or backups. Those copies expire according to the retention policy of the deployment operator.
A recording is the raw meeting audio. For the text of who-said-what with timestamps, use the
transcript — see the
Meetings API.