Call recordings live in S3-compatible object storage (DigitalOcean Spaces or local MinIO per deployment). CXB API proxies them so CRMs get a short, stable URL and the dashboard gets authenticated playback — neither has to handle raw signed Spaces URLs or per-fleet MinIO endpoints. The recording routes and the recording service hold the logic.

Two routers

RouterPrefixAuthLookup 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
The public token is the unguessable recording_access_token minted during results ingestion. CRMs receive https://{host}/api/v1/public/recordings/{token} (built by build_public_recording_url in the call service) instead of a raw signed URL.
Do not send raw Spaces URLs or long signed ?X-Amz-* URLs to CRMs. Some CRMs clip query strings and then storage returns AccessDenied. The stable token URL avoids this and never expires by query signature.

Resolving the recording key

Both routes load the call doc (projecting recording_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:
  1. Object storage — if system settings minio has endpoint/access/secret/bucket, stream the object via boto3 (get_object, 8 KB chunks, Content-Disposition: inline). A NoSuchKey/404 falls through; other storage errors are logged and also fall through.
  2. Fleet fallback — iterate cxbcore_fleet URLs and GET {base}/recordings/{key} with X-CXBCore-Secret. The first 200 wins; 404s and request errors move to the next host. This covers deployments where recordings live on the originating fleet’s local MinIO.
If neither path yields the object, the response is 404.

Storage helpers

The recording service also provides URL helpers used elsewhere (e.g. CRM push fallback and dashboard enrichment):
HelperPurpose
generate_signed_urlPresigned get_object URL (default 24h).
generate_temporary_public_urlShort-lived presigned URL (minutes).
extract_s3_key_from_urlRecover the storage key from a Spaces or legacy MinIO URL.
enrich_call_with_accessible_urlReplace a stored URL with a fresh signed URL for playback.
_region_from_endpoint / _endpoint_urlInfer S3 region (Spaces) and normalise the endpoint scheme.

Operational checks

SymptomFirst place to check
Public link 404Token mismatch, or no recording_key/recording_url on the call.
Storage path silently skippedminio settings incomplete (endpoint/access/secret/bucket).
Fleet fallback never hitscxbcore_fleet empty, or X-CXBCore-Secret mismatch with fleet.
Spaces AccessDenied for CRMCRM 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.

Results ingestion

Where the recording token is minted.

CRM push

How the stable URL is sent to CRMs.

CXB Core post-call

How CXB Core uploads recordings and reports keys.