routes/recordings.py; helpers in services/recording_service.py.
Two routers
| Router | Prefix | Auth | Lookup key |
|---|---|---|---|
| Admin | /api/v1/recordings/{session_id} | require_admin (JWT) | session_id |
| Public | /api/v1/public/recordings/{token} | none (token is the secret) | recording_access_token |
recording_access_token minted during results ingestion. CRMs receive https://{host}/api/v1/public/recordings/{token} (built by build_public_recording_url in call_service.py) instead of a raw signed URL.
Resolving the recording key
Both routes load the call doc (projectingrecording_key, recording_url) and derive the storage key via _recording_key_from_call: prefer the stored recording_key, else take the last path segment of recording_url. A missing call → 404; an undeterminable key → 404.
Streaming with fallback
_stream_recording_key tries object storage first, then falls back to the originating fleet host:
- Object storage — if system settings
miniohas endpoint/access/secret/bucket, stream the object viaboto3(get_object, 8 KB chunks,Content-Disposition: inline). ANoSuchKey/404falls through; other storage errors are logged and also fall through. - Fleet fallback — iterate
voxcore_fleetURLs andGET {base}/recordings/{key}withX-VoxCore-Secret. The first200wins;404s and request errors move to the next host. This covers Ori-style deployments where recordings live on the originating fleet’s local MinIO.
404.
Storage helpers
services/recording_service.py also provides URL helpers used elsewhere (e.g. CRM push fallback and dashboard enrichment):
| Helper | Purpose |
|---|---|
generate_signed_url | Presigned get_object URL (default 24h). |
generate_temporary_public_url | Short-lived presigned URL (minutes). |
extract_s3_key_from_url | Recover the storage key from a Spaces or legacy MinIO URL. |
enrich_call_with_accessible_url | Replace a stored URL with a fresh signed URL for playback. |
_region_from_endpoint / _endpoint_url | Infer S3 region (Spaces) and normalise the endpoint scheme. |
Operational checks
| Symptom | First place to check |
|---|---|
Public link 404 | Token mismatch, or no recording_key/recording_url on the call. |
| Storage path silently skipped | minio settings incomplete (endpoint/access/secret/bucket). |
| Fleet fallback never hits | voxcore_fleet empty, or X-VoxCore-Secret mismatch with fleet. |
Spaces AccessDenied for CRM | CRM was sent a signed URL with query string instead of the token URL. |
| Wrong region on Spaces | _region_from_endpoint inference vs the configured endpoint. |
Related docs
Results ingestion
Where the recording token is minted.
CRM push
How the stable URL is sent to CRMs.
VoxCore post-call
How VoxCore uploads recordings and reports keys.