Skip to main content

Legal holds: preserve recordings and message threads from retention sweeps

Your retention sweep deletes on age. That is the right default until a thread or a recording becomes material to an active legal matter — then age-based deletion destroys evidence you were ordered to keep. The legal-hold console (Settings → Compliance → Legal Holds) is the control you operate when litigation, a regulator, or counsel tells you to preserve: mark a messaging conversation or a voice/video recording as held, give the hold a reason, and the sweep skips it until you release it. Every place and release is written to your audit log with actor, reason, and timestamp, so the evidence trail for the hold itself exists the moment counsel asks for it.
Legal holds are a tenant-owned control: Orbit gives you the switch and the audit evidence; it does not decide what you must preserve, and this page is not legal advice. Confirm your preservation duties with counsel. Holds also interact with GDPR erasure — a record under an active hold is exempt from the retention sweep, and an erasure request routed through your DSAR queue should account for anything your counsel has told you to keep.

What a hold does

Retention in Orbit runs as two age-based sweeps: one for messaging threads, one for voice and video recordings. Either sweep walks its records, and anything older than the retention window you configured is deleted — media files nulled, and rows hard-deleted when your retention policy says so. A legal hold flips a legal_hold flag on the record:
  • Conversations (messaging threads) — placing the hold stamps the flag on the conversation and on every message in it, across every channel the thread spans (SMS, WhatsApp, MMS, RCS, email, web chat). The sweep skips the whole thread while the flag is set.
  • Recordings (voice and video) — the flag covers both the stored media file and the recording’s catalog row, so neither the blob nor the metadata can be reaped while held.
Nothing else changes: held content stays readable and playable in the inbox and recording viewers, and new messages keep flowing into a held conversation. The hold only says “the sweep must not delete this.”

Place a hold

Open Settings → Compliance → Legal Holds. Placing and releasing holds requires the owner or admin role — the backend enforces the same gate on the endpoints, and other roles get the read-only view of the page. The page is two editors side by side, behind the same lookup → hold → verify flow:
  1. Identify the record. You need the conversation id (cnv_…, visible on the thread in the inbox or returned by GET /conversations) or the recording id (rec_…, the recording catalog id). Lookups you have run before stay in the Recent holds list on this device, so a repeat check is one click.
  2. Look up. Paste the id and select Look up. The editor shows the current hold state, and—for a conversation—how many of its messages are already preserved (for example, 148 of 152 if a hold was placed on the thread earlier).
  3. Set the reason. Optional but do it: a reason like SEC 17a-4 litigation — ticket C-1042 or FINRA 4511 — order-date 2026-08-01 is what makes the audit entry legible to counsel six months later. Keep it short; the field caps at a few hundred characters.
  4. Place hold. The state pill flips to On hold. The API equivalent:
Both writes are hold: boolean plus the optional reason, hold the same owner/admin role gate, and take an API key (X-API-Key, live keys prefixed dv_live_sk_) or a dashboard token. Set hold: false to release.

Verify the exemption against your retention policy

Before you tell counsel a record is preserved, verify two things:
  1. The flag is set. Re-run the lookup — the state pill reads On hold. Over the API, GET /api/v1/compliance/legal-hold/conversations/<id> returns legal_hold: true with the reason, the actor, and the last-changed timestamp; for a conversation it also reports message_count and held_message_count so you can confirm the whole thread, not a slice, is covered. Recordings answer the same fields on GET /api/v1/recordings/<id>/legal-hold. When a conversation spans several call legs or video sessions, GET /api/v1/recordings/conversation/<conversationId>/legal-hold returns an aggregate held_recordings of total_recordings tally — a 3 of 4 there is the warning that one leg is unprotected.
  2. The sweep would have deleted it. The exemption only matters if the record’s age exceeds (or is approaching) your configured retention window. A thread your policy keeps for 90 days is safe for a month without a hold; a hold is what stops the deletion once that window elapses. Verify the window you actually configured before relying on the exemption.
Re-check periodically for long-running matters: a missed step above is the difference between “preserved” and “preserved except the newest messages, which nobody re-checked.”

Release the hold and export the evidence

When counsel closes the matter, release the hold — the record returns to normal lifecycle handling and the sweep processes it from its original age, so a five-year-old thread deleted at release is expected behaviour, not data loss. Release. In the console, open the same editor, Look up, and select Release hold (optionally set a closing reason first). Over the API, send hold: false. The ledger records the release with the same actor/reason/timestamp shape as the placement. Evidence. Releasing wipes nothing — the audit entries persist, and the ledger cannot be edited or deleted. To assemble the evidence pack for counsel or an auditor:
  1. Filter the audit log to the legal-hold entries: from the holds page, the Access history panel shows the latest changes and its View full history link opens the audit log pre-scoped to them; you can build the same slice yourself with the audit log’s search and action filters.
  2. Export that filtered view as CSV or JSON from the quick-export buttons (up to 10,000 rows), or queue the uncapped Full export for a complete pull.
  3. The same evidence ships continuously if you subscribe an endpoint to the audit webhook event — hook it into the binder you maintain for your framework; the evidence binder guide covers that assembly.

Fit the hold into your retention posture

Holds are one control in a posture you own end to end:
  • Retention wins by default. Your configured sweeps keep destroying on age until a hold says otherwise — that keeps storage and minimization obligations the norm, with preservation the explicit exception.
  • Erasure requests. A held record still surfaces in a data-subject request — counsel decides whether a litigation duty overrides erasure, and you keep or release per that call. The conversation and recording exports in the conversation archive and the recording catalog give you the DSAR data to review, and the evidence binder packages the resulting attestation.
  • Chain of custody. Because every change is audit-logged, the answer to “who touched this hold, and when” is an export away — review the hold history the way you review the rest of the ledger in the audit log guide.
Run the posture review on a schedule: open the holds page, walk the Recent holds list, and release whatever closed. A hold nobody revisits is a retention posture nobody designed. The console page this guide walks — Settings → Compliance → Legal Holds — keeps three companion surfaces one click away: the audit ledger it writes to (audit log), the archive exports used for DSAR review (conversation archive), and the evidence binder the finished attestation joins (evidence binder). For the full retention-window configuration the exemption defends against, see the recording and messaging retention settings in Settings → Compliance.