> ## 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.

# Recycled-Number Complaint Hygiene: Deactivation, RND, and the List Scrub Working Together

> Keep your recipient list clean as contacts churn: walk the lifecycle of a recycled-number complaint, then run the carrier deactivation scrub, the FCC RND check, and your suppression ledger as one re-engagement hygiene flow.

# Recycled-Number Complaint Hygiene: Deactivation, RND, and the List Scrub Working Together

A phone number is a lease, not a person. A subscriber cancels or lapses,
the carrier deactivates the number and eventually reassigns it, and months
later your re-engagement campaign lands with a stranger who never agreed
to hear from you. That stranger's complaint lands on your sender
reputation, and in the US a text to a reassigned number can carry TCPA
exposure even though the original subscriber opted in. This guide walks
the receiver-side posture: how you keep your list clean as contacts
churn, *before* the recycled number complains.

Everything here is a **tenant-owned control you configure and own**:
Orbit provides the feeds, the check endpoints, and the ledgers; whether
you opt in, how you pace your scrubs, and what you do with a scrubbed
contact are your organization's decisions. This page is **not legal
advice** — confirm your obligations with qualified counsel.

All deactivation endpoints below are rooted at
`https://api.orbit.devotel.io/api/v1/compliance/deactivations`.

***

## 1. Lifecycle of a recycled-number complaint

A recycled-number complaint follows a predictable path:

1. **Churn.** The subscriber cancels, stops paying, or ports away; the
   numbering carrier **deactivates** the number.
2. **Recycling.** After an aging period the carrier returns the number
   to inventory and **reassigns** it to a new subscriber.
3. **Contact.** Your list still holds the number under the old
   relationship, and the next campaign sends to the new subscriber.
4. **Complaint.** The new subscriber marks the message as spam, or their
   counsel claims you messaged a reassigned number without consent.

Three Orbit surfaces catch the number at different points of that path,
and none substitutes for the other two:

| Surface | Question it answers | Catches | Misses |
| - | - | - | - |
| [Carrier deactivation scrub](/compliance/deactivation-scrub) (CRD carrier deactivation daily feed) | Did the carrier disconnect this number since I last validated the relationship? | Churn at deactivation, *before* reassignment, often the same day | What the person asked for; numbers you never dated a relationship for |
| [RND scrub](/compliance/rnd-scrub) (FCC Reassigned Numbers Database) | Was this number reported permanently disconnected since my consent date? | Reassigned numbers, with the FCC TCPA safe harbor behind the check | Deactivations not yet published to the RND; anything about consent itself |
| [DNC and opt-out suppression](/compliance/dnc-scrub) | Did this person ask me to stop? | Expressed intent: STOP replies, complaints, preference-center choices | Every number where the *person* changed but nobody opted out |

Run them as a stack, in that order: the deactivation feed sweeps churn
out of your list early, the RND check screens what remains before
contact, and the suppression ledger gates every send. A number that
passes all three has a live relationship, a current holder, and no
standing objection.

## 2. The hygiene runbook

Work these steps before every re-engagement campaign, and on a schedule
for long-lived lists. Each step's copy-paste request is in §3.

### Step 1: Enable the deactivation scrub

The scrub is a per-organization opt-in and defaults to off. Read your
current state with `GET /deactivations/settings`, then flip it with
`PUT /deactivations/settings` (owner/admin only). The response carries
`feed_synced`; while it is `false` no carrier snapshot is loaded and
every verdict degrades to `no_data`, so enable the toggle first and
confirm the feed before trusting a clear result.

### Step 2: Pre-flight before the campaign

Check one number with `GET /deactivations/check` while you are wiring
things up, then run the audience through `POST /deactivations/scrub` in
pages of up to 1,000 numbers before the audience is frozen. Pass
`last_seen` as the date you last validated each relationship (the most
recent consent or two-way interaction); deactivations strictly before
that date are ignored, because the relationship postdates them. Omit
`last_seen` only for cold lists and imports with no validated date to
defend. Drop every `should_scrub: true` row from the campaign, and store
the verdict and the `last_seen` you used on the contact record so the
next sweep only re-checks contacts whose state aged.

### Step 3: Stack with your suppression entry points

A clean deactivation verdict does not exempt a number from the
suppression ledger: the audience that survives the scrub still passes
your opt-out gates at send time. Keep one of the three entry points as
the owner of your STOP ledger, per
[Choose your suppression entry point](/guides/suppression-three-entry-points)
(CSV import, Consent API, or Preference Center). Keep the ledgers
separate in the other direction too: a deactivation verdict is a
*carrier* network event, not a person's instruction, so route
`should_scrub: true` rows to a contact-status field (for example
`carrier_deactivated` with the `last_deactivation_date`) rather than
writing them into suppression as if they were STOP replies. If the new
holder of a recycled number texts STOP, that opt-out enters suppression
through the normal keyword path. One ledger per truth; see
[Opt-Out & Suppression Lists](/compliance/opt-out-suppression) and
[Message suppression](/guides/message-suppression).

### Step 4: Tie the scrub to the subscriber-relation clock

Consent records carry a `valid_until` (or `expires_in_days`) window that
defines how long the relationship counts as validated; a grant past its
`valid_until` reads `expired: true` and should be treated as
no-longer-consented at your send gate, per
[Consent Management & Receipts](/compliance/consent-management). Sweep
`GET /compliance/consent/expiring` on a schedule (`within_days=30` is a
sensible horizon) and treat every returned grant as a scrub candidate:
run that cohort through `POST /deactivations/scrub` with
`last_seen` set to the grant's most recent validated date, and drop the
scrubbed rows before you plan any re-permission send. A scrubbed number
re-enters your sendable pool only through a fresh opt-in recorded via
the Consent API whose new consent date postdates the carrier's
`last_deactivation_date`. Consent windows therefore drive the scrub
cadence: stale numbers are scrubbed per window, not discovered per
complaint.

## 3. curl examples

Read the org opt-in and the feed state:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/deactivations/settings" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Enable the scrub for your organization (owner/admin):

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/compliance/deactivations/settings" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
```

Pre-flight one number against the date you last validated it:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/deactivations/check?phone=%2B14155550101&last_seen=2026-04-01" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Scrub a page of the re-engagement audience; a top-level `last_seen`
applies to every number unless a per-number `last_seen` overrides it:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/compliance/deactivations/scrub" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "last_seen": "2026-04-01",
        "numbers": [
          {"phone": "+14155550101"},
          {"phone": "+14155550102", "last_seen": "2026-06-15"}
        ]
      }'
```

Read the response as: `scrub_count + kept_count` equals `checked`, and
your drop list is exactly the rows with `should_scrub: true`. While
`feed_synced` is `false`, expect `no_data` verdicts and do not treat
them as clear.

Find consent grants whose validation window has lapsed or is about to,
as the input cohort for step 4:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/consent/expiring?within_days=30&status=all" \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

## 4. Caveat: the scrub is opt-in and fail-open

<Warning>
  The deactivation scrub is a configuration **you** enable; it is not a
  platform-wide block applied to every tenant. Until your organization
  sets `enabled: true`, the check and scrub endpoints answer
  `403 DEACTIVATION_SCRUB_NOT_ENABLED` and your sends proceed unguarded
  by the carrier feed, exactly as with the other opt-in gates described
  in [Send Gates](/compliance/send-gates). Once enabled, lookups also
  fail open: with no snapshot loaded (`feed_synced: false`) or on a
  degraded lookup, verdicts degrade to `no_data` /
  `should_scrub: false` rather than blocking you. A clear verdict is
  therefore never a safe harbor by itself. Keep the stack layered
  (deactivation feed, [RND safe-harbor check](/guides/rnd-safe-harbor-preflight),
  suppression ledger) and verify `feed_synced` before you rely on it.
</Warning>

***

## 5. Related reading

* [Carrier Deactivation (Churn) Scrub](/compliance/deactivation-scrub) —
  the reference page: field matrix, send-path guard semantics, fail-open
  caveat.
* [RND Scrub: FCC Reassigned Numbers Database Reference](/compliance/rnd-scrub) —
  the reassigned-number leg and its safe-harbor posture.
* [DNC Scrubbing: Sources, Freshness, and the Check Endpoint](/compliance/dnc-scrub) —
  the registry-side "did the person ask to stop?" leg.
* [Send Gates](/compliance/send-gates) — how the deactivation, RND, DNC,
  and suppression gates layer at send time.
* [Choose your suppression entry point](/guides/suppression-three-entry-points) —
  CSV import, Consent API, or Preference Center as the owner of your
  STOP ledger.
* [Message suppression](/guides/message-suppression) — the send-time
  dedupe and suppression behavior the ledger feeds.
* [Deactivation-Scrub List Hygiene Runbook](/guides/deactivation-scrub-minimization-runbook) —
  the sender-side lifecycle this receiver-side posture pairs with.
* [RND Safe-Harbor Pre-Contact Number Scrubbing](/guides/rnd-safe-harbor-preflight) —
  pre-contact RND screening for re-engagement audiences.
* [Batch DNC Pre-Flight Scrubbing](/guides/dnc-preflight-scrub) — batch
  DNC screening to run alongside the deactivation scrub.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.