> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Per-Domain Data Retention Policy

> Set message-body redaction, closed-conversation hard-delete, and audit-log purge windows per domain — the tenant-owned GDPR Art. 5(1)(e) storage-limitation surface

# Per-Domain Data Retention Policy

The data-retention policy decides how long three classes of records stay
intact in your workspace before scheduled sweeps redact or delete them. It
is three **independent domains** behind one endpoint pair — message-body
redaction, closed-conversation hard-delete, and audit-log purge — each with
its own window and its own minimum and maximum allowed values. All three
domains are **disabled by default**: a workspace that never touches this
surface has no automatic retention behavior.

```
GET /api/v1/compliance/data-retention
PUT /api/v1/compliance/data-retention
```

<Warning>
  This page describes Orbit's platform controls. It is **not legal advice.**
  How long you may or must keep messages, conversations, and audit evidence
  depends on your regulators, your contracts, and your counsel's reading of
  them. Confirm the specifics with qualified counsel.
</Warning>

***

## The three domains

Each domain answers one storage-limitation question, and you can enable any
combination of them.

### Message-body redaction (`messages`)

After the number of days you configure, a scheduled sweep replaces the
message body and the recipient/sender identifiers with a redacted marker.
Billing-grade metadata — status, segment count, price, carrier error — and
the delivery-receipt and audit trail survive intact, so finance and dispute
lookback still work on redacted rows. Set the window to `0` to disable the
sweep; any enabled value must sit within the allowed bounds.

* Allowed window: **7 to 3650 days** (or `0` to disable).

### Closed-conversation hard-delete (`conversations`)

When enabled, a scheduled sweep hard-deletes a conversation row once it has
been **closed** longer than your window. The message rows attached to the
conversation are not deleted with it, so billing and audit metadata survive
the purge. Only closed conversations are eligible; an open thread is never
swept.

* Allowed window: **30 to 3650 days**. The 30-day floor prevents a purge of
  a conversation that closed only hours ago.
* If you enable this domain without a window, the platform default of
  **180 days** applies.

### Audit-log purge (`audit_logs`)

When enabled, a scheduled sweep hard-deletes audit log entries older than
your window. Audit logs are the evidence trail for every configuration
change in your workspace, so this domain carries a regulatory floor.

* Allowed window: **365 to 3650 days**. The 365-day floor protects the
  SOC 2 examination window — you can never purge audit evidence younger
  than one year.
* If you enable this domain without a window, the platform default of
  **2190 days** (six years) applies, targeting HIPAA's retention
  expectation.

<Note>
  DSAR erasure is separate from this age-based policy. A data-subject
  request scoped to a contact runs its own workflow independently of these
  org-wide windows — see [Data Subject Requests](/compliance/dsar).
</Note>

***

## Read the resolved policy

```bash theme={null}
curl https://api.orbit.devotel.io/api/v1/compliance/data-retention \
  -H "X-API-Key: dv_live_sk_..."
```

```json theme={null}
{
  "data": {
    "messages": { "redact_body_after_days": 90 },
    "conversations": { "enabled": true, "delete_closed_after_days": 180 },
    "audit_logs": { "enabled": false, "delete_after_days": 2190 },
    "bounds": {
      "messages": { "redact_body_min_days": 7, "redact_body_max_days": 3650 },
      "conversations": { "delete_closed_min_days": 30, "delete_closed_max_days": 3650 },
      "audit_logs": { "delete_min_days": 365, "delete_max_days": 3650 }
    }
  }
}
```

The response always returns the resolved value for every domain, plus a
`bounds` object carrying the allowed min/max window for each — the same
values the dashboard uses to clamp inputs. Read is any authenticated role;
a fresh workspace returns the defaults above with all three domains
disabled.

***

## Write the policy

Writes require an **owner or admin** API key or dashboard role — retention
is a regulatory control, so the gate mirrors the rest of the compliance
write surface. Any other role receives `403`.

The write is **merge-on-write**: each domain block is optional, and a block
you omit keeps its stored value. Send only the domains you intend to
change.

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/compliance/data-retention \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "messages": { "redact_body_after_days": 90 },
    "conversations": { "enabled": true, "delete_closed_after_days": 180 }
  }'
```

Rules to build against:

* **Provide at least one domain** — an empty body returns `422
  VALIDATION_ERROR`.
* **In-range values are validated strictly.** A `redact_body_after_days`
  enabled value outside the bounds, or a window outside its min/max,
  returns `422` with a per-field error.
* **Resolution is permissive on enable-without-window.** For
  `conversations` and `audit_logs`, sending `enabled: true` without a
  window resolves to the platform default (180 and 2190 days
  respectively); the resolved values are what the sweeps use, and the
  response of a write is the same resolved view as `GET`.
* **Every change is recorded.** Each write lands in your audit log with the
  domains changed and the actor, preserving the governance trail for the
  policy itself.

***

## Execution model: sweeps, not immediate deletion

The endpoint records policy only. Writing a 90-day window does **not**
redact anything at the moment you save it — enforcement runs in scheduled
background sweeps that apply your resolved policy on their own cadence.
Plan your runbook accordingly:

* A record older than its window becomes eligible for the sweep, and is
  redacted or deleted on the next sweep run — not at the instant it crosses
  the window.
* Tightening a window (for example, 365 days to 90 days) queues the newly
  over-window records for the next sweep. It is not a synchronous purge.
* Relaxing or disabling a window stops future sweeps from redacting or
  deleting beyond what the new policy allows; records already redacted or
  deleted are not restored.

Read the policy back with `GET` to confirm the resolved values before you
rely on them in an internal procedure.

***

## GDPR Art. 5(1)(e): why the policy exists

Article 5(1)(e) of the GDPR frames storage limitation: personal data must
be kept in a form that permits identification of data subjects **for no
longer than is necessary** for the purposes it was collected for. For a
CPaaS operator, the records that attract this principle are exactly the
three domains on this page — message bodies carry customer content,
conversations carry the thread history, and audit logs carry the workspace
trail.

The per-domain policy exists so you can express a storage-limitation
posture as configuration: short windows where minimization matters
(message bodies), longer windows where a regulatory floor argues otherwise
(audit logs), and each domain reached independently because a single global
TTL never fits all three. The 365-day audit floor is an example of the
platform holding a **regulatory minimum** for you — it stops a mis-set
window from destroying SOC 2 evidence, not a limit on how aggressive your
posture can be elsewhere.

Your counsel decides the windows. The platform enforces them and records
every change to the policy itself.

***

## Interaction with legal hold and archival export

Retention sweeps are deletion machinery, so they share space with two
preservation controls:

* **[Legal holds](/compliance/legal-hold).** A hold on a conversation
  exempts that thread from the retention machinery for as long as the hold
  stands — the sweep skips it. A hold is the litigation-preservation
  posture; the retention policy is the normal-operation posture, and the
  hold wins while it stands. Set the policy for the workspace default and
  use holds for the exceptions.
* **[Immutable archival export](/compliance/archival-export).** Archival
  copies messages and call recordings into a tamper-evident bundle in your
  own WORM or S3 store. If your obligations outlive your retention windows,
  archive **before** the sweeps start deleting — retention answers "how
  long does Orbit hold this," archival answers "how do I hold my own copy."
* **Erasure requests.** DSAR erasure runs contact-scoped and independently
  of this age-based policy; reconcile open erasure requests against holds
  as part of your DSAR process rather than expecting the retention windows
  to fulfil them.

***

## Your retention posture stays yours

The per-domain retention policy is a **tenant-owned control**: Orbit
provides the windows, the sweeps, and the audit trail — what the windows
are, and which domains apply to your posture, are your decisions. All three
domains stay disabled until you enable them, and every enable, change, and
disable is a decision your owners and admins made, recorded in your audit
log. For the wider assembly — consent records, DSAR intake, the register,
the evidence binder — walk the [GDPR posture guide](/compliance/gdpr-posture-guide).

***

## Related

<CardGroup cols={2}>
  <Card title="Legal Holds" href="/compliance/legal-hold">
    Exempt a conversation from retention sweeps for litigation preservation.
  </Card>

  <Card title="Immutable Archival Export" href="/compliance/archival-export">
    Copy records into a tamper-evident bundle before the sweeps delete them.
  </Card>

  <Card title="GDPR Posture Guide" href="/compliance/gdpr-posture-guide">
    Assemble the full GDPR posture — consent, DSAR, the register, and the binder.
  </Card>

  <Card title="Data Subject Requests" href="/compliance/dsar">
    Contact-scoped access and erasure, and how to reconcile them with holds.
  </Card>
</CardGroup>
