Skip to main content

Voice call recordings to your own bucket (BYO storage)

By default, a call recording lands on Orbit-managed object storage. Regulated tenants often need more than that default: the recording must land in a bucket the tenant owns so the audio archive sits in their own cloud account — which is also where their own knowledge-ingest and quality pipelines read it back from. The recording_storage organization setting gives you that control for voice recordings. It is the standing, organization-level analogue of the per-request recording_storage field on video rooms: you set it once, and every call recording on the account is routed to the declared destination. There is no request-body field on call start or recording start — call recordings are asynchronous, so the destination comes from your organization’s stored configuration.

1. What goes into the BYO bucket

Voice recording BYO storage currently moves one artifact class:
  • Call recordings — the finalized audio file for each recorded call. The object lands under recordings/<tenant>/<callId>.mp3 inside the destination bucket (or under your configured prefix instead of recordings). The recording metadata — the gs:// path, duration, and transcript — is still recorded against the call in Orbit, so the call log and QA surfaces keep working exactly as before.
What stays in platform storage, by design:
  • Transcripts and QA artifacts — transcription, quality-evaluation, and sentiment outputs live in your workspace data, not as objects in the bucket. The recording’s transcript is stored with the call record (and reachable through the recordings API), not written as a second object.
  • The object-path record — Orbit records the gs://<bucket>/<object> path of every recording so read-back and audit surfaces can point at it. That descriptor never carries credentials.
  • Video room recordings — a separate, per-request control. See the video room BYO storage guide; do not infer its per-request behaviour onto calls.
This is deliberate: the bucket carries the regulated audio; the workspace keeps the derived metadata the product surfaces need.

2. Bucket and IAM setup

The supported BYO destination for call recordings is a Google Cloud Storage bucket you own. Create a dedicated bucket for call recordings — do not reuse a general-purpose bucket. Orbit’s recording service authenticates to your bucket with its workload identity (the cross-project grant case): there is no service-account JSON key to register and no persisted secret. What Orbit needs from you is a grant, not a credential. Grant the role on the bucket only, to Orbit’s recording service account:
  • roles/storage.objectCreator — lets the recording upload write new objects into the bucket.
  • Nothing else. Do not grant roles/storage.admin (too broad), do not grant at the project level, and do not add list/delete permissions you have no use for — least privilege is the whole point of BYO.
If your read-back path also reads objects (for example, an in-house ingest pipeline that pulls recordings out of the bucket), that is a separate identity — your pipeline’s service account holding roles/storage.objectViewer on the same bucket. Keep the two grants separate so each identity carries only the scope it needs.
An S3 destination is accepted on the setting for parity with the video-room surface, but the synchronous call-recording path cannot honour it today — an S3-configured organization falls back to Orbit-managed storage for call recordings while the configuration is preserved. Use GCS for BYO call recordings.

3. Register the bucket

Recording storage is an organization setting. Set it through the settings API (PUT /api/v1/organization/settings) — the same endpoint-backplane that the dashboard’s organization settings use:
Field rules, matching what the read-write boundary accepts:
  • provider"gcs" for a customer bucket, "orbit" for Orbit-managed storage.
  • bucket — a valid bucket name: lowercase alphanumerics plus ., _, and -; 3–255 chars; must start and end alphanumeric.
  • prefix — optional object-key prefix. Restricted to [A-Za-z0-9._/-]; traversal segments (..) are stripped. When omitted, objects land under recordings/.
  • region — meaningful only for provider: "orbit" (a data-residency audit pin; see Pin a region, below).
Only the descriptor above is ever stored — provider, bucket, prefix. There are no credentials in the payload, so nothing secret enters your organization settings, the API response, or the audit log. To revert to Orbit-managed storage, set recording_storage back to null (or { "provider": "orbit" }).

Verify with a write-and-read probe

After registering, confirm the route end to end:
  1. Place a short test call with recording enabled and let it finalize.
  2. In your bucket, confirm a new object appeared under recordings/<tenant>/<callId>.mp3 (or under your prefix). The object key is also visible in the call’s recording metadata — compare it against the object that landed.
  3. Fetch the call’s recording in the dashboard or via the recordings API — the metadata should point at the gs:// path in your bucket, and playback (see Reading a recording back, below) should succeed.
If the object did not arrive but the call shows a recording path, the destination was not honoured — check the IAM grant on the bucket and the bucket name, then re-run the probe.

4. Where the write path lands

Object keys are deterministic so a pipeline can address them without a lookup: <tenant> is the tenant-scoped folder name portion of your organization’s storage path; <callId> is the call identifier already present in your call logs and webhooks. Transcripts and QA artifacts are not objects — they live in the workspace data (see §1).

5. Reading a recording back

There are two read-back paths and they serve different audiences:
  • QA and dashboard surfaces — Orbit’s recording library, call log, and QA panels read the recording through a presigned URL the platform mints for the object path on demand. Nothing changes for those surfaces when you go BYO: they still resolve the stored gs:// path to a time-limited playable URL the same way they do for Orbit-managed storage.
  • Your own systems — because the bucket is yours, your own tooling can also read objects directly with your own credentials (for example, a gsutil/storage client or a signed URL minted by your own service account). Use this for bulk export or an ingest pipeline; the platform’s presigned URL is for the QA surfaces and single-recording playback.
If a recording exists in your bucket but QA playback fails, the stored object path and the actual object disagree — compare the path in the call’s metadata against the object key in the bucket.

6. The SIPREC uploader side

The SIPREC recording-ingest pipeline (the service that receives SIPREC-recorder pushes) supports the same BYO convention: when your organization has a customer GCS destination configured, SIPREC uploads land in your bucket under the same recordings/<tenant>/<callId> object-key shape, and the stored gs:// path points into your account. If you ingest via SIPREC (call recording from your own SBC/recorder rather than Orbit’s outbound call recording), the registration is the same one — there is no second setting to manage. This guide otherwise scopes itself to CCaaS (Orbit call) recordings; the mechanics above are the ones you run for that path.

7. Lifecycle: retention and deletion hooks are yours

Orbit records the object path but does not enforce retention on customer bucket objects. Retention of the audio is the bucket’s own lifecycle policy:
  • Set a GCS lifecycle rule on the bucket — for example, delete objects 90 days (or your policy’s window) after creation — and that policy owns expiry, not Orbit.
  • Deleting or expiring an object in the bucket does not retro-edit the recording metadata; the workspace keeps the gs:// path record, and read-back then fails when the object is gone (see the next section). If you need the workspace to forget the recording too, act on it through the recordings API (retention / delete there) rather than only emptying the bucket.
This split is intentional: the audio’s retention is a tenant control; the workspace metadata is a platform ledger.

8. Credential rotation and misconfiguration: the read-back error modes

Because there is no persisted credential on the Orbit side, “credential rotation” reduces to the IAM grant — if you rotate the underlying service account on your side, the Orbit-side grant still names Orbit’s recording service account and remains valid. The failure modes that actually surface are destination-side:
  • Upload rejected — the recording upload was denied (grant revoked, wrong bucket name, bucket deleted). The recording is preserved on Orbit-managed storage rather than lost, and the stored destination falls back; fix the grant or bucket and subsequent recordings honour BYO again.
  • QA playback fails with a read-back error — the stored gs:// path resolves to an object that no longer exists (lifecycle expired it early, or it was deleted in the bucket). The metadata is intact but the object is gone; there is no platform copy to fall back to once the original upload was honoured.
  • Malformed destination rejected at write — an invalid bucket name or out-of-set prefix character fails the settings write (PUT /organization/settings) with a validation error before it reaches any upload path.

9. Worked example: a HIPAA tenant under a BAA imposing BYO storage

A healthcare contact-center tenant signs a BAA that requires call recordings (potential PHI) to live in cloud storage the covered entity controls.
  1. Provision the bucket in the tenant’s own GCP project: acme-health-recordings, uniform bucket-level access, no public access.
  2. Grant Orbit’s recording service account roles/storage.objectCreator on that one bucket — write-only on the bucket, nothing at project scope.
  3. Register the destination:
  4. Run the write-and-read probe with a test call, confirm the object lands under recordings/<tenant>/<callId>.mp3 in the tenant’s bucket, and confirm QA playback still works through the dashboard.
  5. Set the bucket lifecycle to the tenant’s HIPAA retention schedule (for example, delete after the BAA’s agreed retention window).
The tenant’s HIPAA posture then records the bucket as an in-scope destination in its processing-records catalogue. The BAA-gated toggle that this destination rolls up under is covered in the HIPAA compliance guide; the key-management posture that complements object residency is covered in the BYOK (customer-managed keys) guide.

Where to go next