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

# RND Safe-Harbor Pre-Contact Number Scrubbing

> Scrub destination numbers against the FCC Reassigned Numbers Database before you text or call — the per-org opt-in gate, feed-sync semantics, single-number checks, and pre-campaign batching.

# RND Safe-Harbor Pre-Contact Number Scrubbing

An RND scrub answers one question before a campaign leaves the building:
**is this destination number still assigned to the person who consented?**
Under the TCPA, consent follows the subscriber, not the number — when a
carrier re-assigns a number to a new subscriber, your consent for the old
subscriber stops covering that destination. The FCC's Reassigned Numbers
Database (RND — [reassigned.us](https://www.reassigned.us),
47 CFR § 64.1200(m)) exists to answer one specific question: **was this
number permanently disconnected after my consent date?**

Orbit exposes the FCC safe-harbor evaluation as a read-only lookup:

* `GET /compliance/rnd/check` — one E.164 number plus the date you obtained
  (or last verified) prior-express consent, returning an FCC RND verdict
  and whether the safe harbor applies.

Read-only — a check never performs a send. Use it before any outbound SMS
or voice initiation so the send path only ever sees destinations that
passed the reassignment screen.

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

<Warning>
  This page describes Orbit's platform controls. It is **not legal
  advice.** Whether contacting a given number is restricted depends on
  your jurisdiction, your recipients, and what you send — confirm with
  qualified counsel.
</Warning>

***

## How RND differs from the other scrubs

DNC, litigator, suppression, and carrier-deactivation scrubs all answer
"did they opt out / is the destination still a live line?" RND answers the
orthogonal question: "is this destination still the person who consented?"

| Question                                                                                | Endpoint                                         | What it checks                                                                          |
| --------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------- |
| Did the person ask to stop / is the number on a restricted registry?                    | [`/compliance/dnc/check`](/compliance/dnc-scrub) | Federal/state/TCR/international DNC registries plus your suppression and consent layers |
| Did the subscriber's carrier deactivate this number since your last valid relationship? | `/compliance/deactivations/check`                | Carrier disconnect/churn feed vs. an optional last-validation date                      |
| Was this number permanently disconnected **after my consent date** (TCPA safe-harbor)?  | `/compliance/rnd/check`                          | FCC Reassigned Numbers Database: permanent-disconnect date vs. consent date             |

Run RND **alongside** the DNC scrub, not instead of it — a number can be
reassigned without ever touching a registry, and registry-listed without
reassignment getting involved. See [DNC Scrubbing](/compliance/dnc-scrub)
and [Phone Deactivation Scrubbing](/compliance/deactivation-scrub) for
those checks; this guide covers the RND leg.

***

## Enable the per-org toggle

The endpoint is gated behind your organization's RND-scrub opt-in —
`organizations.settings.rnd_scrub_enabled`, default **off**. While the
flag is off, every `/rnd/check` returns HTTP 403:

```json theme={null}
{
  "error": {
    "code": "RND_SCRUB_NOT_ENABLED",
    "status": 403,
    "details": { "flag": "organizations.settings.rnd_scrub_enabled", "feed_synced": false }
  }
}
```

**Enabling requires a synced feed.** The FCC RND is a paid subscription
(data administrator: SomosGov / reassigned.us); Orbit ingests the snapshot
at API boot from `DEVOTEL_RND_FEED_FILE` / `DEVOTEL_RND_FEED_URL` once
the subscription is provisioned. Until that ingestion has succeeded,
turning the toggle **on** is refused with HTTP 409
`RND_FEED_NOT_CONFIGURED` — the control is only offered once the feed is
ingested, so a tenant cannot switch on an inert compliance control.
(Company-operated configuration; you cannot enable it yourself while
`feed_synced` is false.) Disabling is always allowed. The PUT is
owner/admin-only: flipping it requires an owner or admin on your team.

Check the gate state without scrubbing anything:

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

```json theme={null}
{
  "enabled": true,
  "feed_synced": true
}
```

To toggle (owner/admin): `PUT /compliance/rnd/settings` with body
`{ "enabled": true }`. A single setting change takes effect immediately.

<Note>
  **Check `feed_synced` before you check numbers.** It reports whether an
  RND disconnect snapshot is loaded; while no feed is configured, every
  `/rnd/check` verdict is `no_data`. A waiting-for-feed 409 on enable is
  the gate protecting you from enabling an inert control — it is the
  correct state, not an error to retry.
</Note>

***

## Feed status — `feed_synced` on every verdict

Every `/rnd/check` response carries `feed_synced`. Read it before trusting
a verdict:

* **`true`** — the ingested RND snapshot backed this verdict (real data).
* **`false`** — no feed is loaded, or the feed lookup itself failed. Verdict
  degrades to `no_data` **on every number**, and `safe_harbor` is `false` —
  we cannot claim a sync we did not complete. Never treat a `false` response
  as a real "not reassigned" answer; treat it as UNKNOWN and gate the send.

The platform never asserts a safe harbor it has not actually queried —
when the feed is missing or broken, the answer is conservatively
"no data" rather than silently pass.

***

## Single-number check

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

* `phone` — E.164 destination (leading `+`, 7-15 digits).
* `consent_date` — ISO calendar date (YYYY-MM-DD) you obtained or last
  verified prior-express consent.

Response shape (one result per number):

```json theme={null}
{
  "data": {
    "status": "no",
    "safe_harbor": true,
    "last_disconnect_date": "2025-11-02",
    "consent_date": "2026-08-15",
    "feed_synced": true,
    "reason": "No permanent disconnect after the consent date; the FCC reassigned-number safe harbor applies — safe to contact."
  }
}
```

The `status` verdict has three values:

| `status`  | Meaning                                                                                                                         | `safe_harbor` |
| --------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `no`      | No permanent disconnect on record after the consent date — the FCC safe harbor **applies**                                      | `true`        |
| `yes`     | The number was permanently disconnected **after** the consent date and may have been reassigned — **do not contact**            | `false`       |
| `no_data` | The synced feed has no permanent-disconnect record for this number (or no feed is loaded) — the caller proceeds at its own risk | `false`       |

`last_disconnect_date` (ISO-8601, or `null`) is the most-recent permanent
disconnect on record — the date the safe-harbor comparison ran against.
`reason` is a one-sentence explanation suitable for an audit log.

<Note>
  Every scrub is audit-logged with the verdict, `safe_harbor`, and consent
  date, so a compliance review can prove the pre-contact check ran. Phone
  numbers are truncated in the audit details (first 5 digits → `****`).
</Note>

***

## Pre-campaign batch pattern

There is no batch endpoint — batching is a loop over the single check.
Run it between building the audience and launching the campaign:

1. **Build your segment** with the audiences/CDP tools as usual.
2. **Resolve a consent date per recipient** — the date you obtained (or
   last verified) prior-express consent. One date per segment, or per
   contact if consent ages diverge.
3. **Check the gate** — `GET /compliance/rnd/settings`. If `enabled` or
   `feed_synced` is false, fix that first (above).
4. **Loop the segment** and call `/rnd/check` per number. The endpoint
   shares the standard authenticated-read budget (120 requests/minute per
   organization). Chunk the audience and call sequentially with a small
   pause (\~500 ms) per request; a loop that fires in a tight burst hits
   HTTP 429 and pauses.
5. **Route the verdicts** out of the send audience:
   * `yes` → suppress the destination (and log it under your
     [suppression](/compliance/opt-out-suppression) layer so future
     segments exclude it up front). Do not attempt to send.
   * `no_data` → treat as UNKNOWN: either hold until the feed is synced or
     send under your own risk policy — it is **not** a safe-harbor pass.
   * `no` → eligible for the campaign (safe harbor covers it).
6. **Launch** against the scrubbed audience — see
   [Outbound dialer campaigns](/guides/outbound-dialer-campaign) and
   [Campaign end-to-end](/guides/campaign-end-to-end).
7. **Re-scrub stale audiences.** The RND is updated by carriers
   continuously, so re-run before each send for an audience held more
   than a couple of days. The verdict you ran at audience-build time
   ages out as disconnect records move.

***

## Failure modes and per-number handling

The check never throws at the route level — a scrub gate degrades to a
conservative `no_data` instead of breaking your flow. Per-number realities:

* **Bad `phone` / bad `consent_date`** → HTTP 422 with the failing
  field(s) in `details`. Fix the shape and retry; the verdict layer never
  sees it.
* **Feed lookup fails or no feed is loaded** → `status: "no_data"`,
  `safe_harbor: false`, `feed_synced: false`, and `last_disconnect_date:
  null`. Route `no_data` per your own risk policy — it is never a
  safe-harbor pass.
* **Unparseable consent date at the verdict layer** → `no_data` with a
  specific reason; the controller's `YYYY-MM-DD` regex keeps this from
  reaching the verdict in normal use, but an old SDK that skips validation
  gets the same safe degradation.
* **HTTP 403 `RND_SCRUB_NOT_ENABLED` on every call** → the per-org opt-in
  is off; the dashboard's scrub card greys or enables the action up front
  via `GET /compliance/rnd/settings`.
* **HTTP 409 `RND_FEED_NOT_CONFIGURED` on enable** → the FCC feed is not
  ingested; the toggle cannot turn on yet. This is the gate at work, not
  a failed call.

Rate limits: read `/rnd/settings` and `/rnd/check` against the standard
authenticated-read budget (120/min per org); writes (`PUT /rnd/settings`)
are 20/min, owner/admin only.

***

## Audit and logging caution

Every scrub is written to the audit chain (with the phone truncated to its
first five digits) so a compliance review can show the pre-contact ran
before the send went out. That record exists to show *your side* of the
TCPA exposure.

The goal of running a scrub is not to produce a textual "clear" verdict —
`safe_harbor: true` only follows `status: "no"`. A clean run of `no_data`
verdicts is a signal the screen did not run, and you gated the send on
"unknown" data; feed it back to your suppression layer, not to a send
queue.

<Warning>
  This guide is **general guidance on tenant-owned controls**, not legal
  advice. Whether contacting a given number is restricted, and whether the
  FCC safe harbor covers your specific campaign, depends on your
  jurisdiction, your recipients, and what you send. Confirm with qualified
  counsel before relying on the verdict.
</Warning>

***

See also:

* [DNC Scrubbing](/compliance/dnc-scrub) — the opt-out registry layer.
* [Phone Deactivation Scrubbing](/compliance/deactivation-scrub) — the
  carrier disconnect/churn layer, including the scrub-vs-send-gate
  comparison table above.
* [Send Gates](/compliance/send-gates) — the quiet-hours / DNC / RND /
  RMD gates that run at send time.
* [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) — the
  layer a `yes` verdict routes onto.
* [Your Tenant Compliance Posture](/compliance/posture-overview) — the
  toggle map, including the RND-scrub row.
* [API Reference → Compliance](/api-reference/endpoints/compliance) —
  full request/response schemas.
