Deactivation-Scrub List Hygiene Runbook: Integrate the Carrier Feed Into Your Churn Lifecycle
A list decays the day it is exported. Subscribers cancel lines, let ports lapse, and carriers reclaim and reassign numbers — so by campaign day, a fraction of any audience points at strangers or at dead lines. The deactivation scrub gives you the carrier disconnect feed as an API; this runbook assembles it into a lifecycle you run per contact: release a number → scrub its new state → reverify before the next send → repeat, instead of treating scrubbing as a one-time pre-flight. Everything here is a tenant-owned control you configure and own: Orbit provides the feed, the API, and the send-path guards; whether you opt in, what you do with adeactivated verdict, and how you pace
reverification are your organization’s choices. This page is not legal
advice — confirm your obligations with qualified counsel.
All endpoints below are rooted at
https://api.orbit.devotel.io/api/v1/compliance/deactivations.
1. What the deactivation scrub does
The scrub answers one operational question: did the subscriber’s carrier deactivate this number since you last had a valid relationship with them? Numbering carriers publish a daily feed of deactivated or disconnected numbers; Orbit ingests it centrally and exposes it as:GET /deactivations/check— one E.164 number, verdict +should_scrubboolean.POST /deactivations/scrub— up to 1,000 numbers per request, the pre-campaign batch leg.PUT /deactivations/settings— the per-organization opt-in (deactivation_scrub_enabled), owner/admin-only.
feed_synced: while no carrier snapshot is loaded,
every verdict degrades to no_data and should_scrub: false — read it
before you trust a clear verdict. The full field matrix, the send-path
guards (MESSAGING_NUMBER_DEACTIVATED on SMS/MMS,
VERIFY_NUMBER_DEACTIVATED on OTP), and the fail-open caveat are covered
on the reference page; do not duplicate
that reading here — this runbook is the operating layer.
2. Integrate it into the churn lifecycle
Scrub once at import and you ship a stale list next quarter. Wire the three gates so lifecycle state changes on a contact always go through the feed:- Number-release sweep. When your own inventory releases a sender or
a destination record ages past its revalidation window (for example a
contact not messaged in 90 days), queue the number for a
deactivations/checkbefore its next inclusion in any audience. - Scrub on campaign assembly. Before a campaign audience is frozen,
run
POST /deactivations/scrubin 1,000-number pages with alast_seenequal to the date you last validated each relationship (typically the most recent consent or successful two-way interaction). Drop everyshould_scrub: truerow. - Reverify per contact. A number that came back
deactivatedis not lost forever — it needs a new relationship event: the subscriber re-joins, confirms the number on a fresh channel, or you record new prior-express consent dated after the carrier’slast_deactivation_date. Re-run the check with that newerlast_seen; only then does the contact re-enter lists.
last_seen you used on the contact record, so the next
sweep only re-checks contacts whose state aged.
3. Pre-send gate syntax and what happens on recycled numbers
The manual check’s only real decision is thelast_seen filter:
- Omit
last_seen— any deactivation record on file scrubs the number. Use this for cold lists and imports, where you have no validated relationship date to defend. - Supply
last_seen— deactivations strictly before that date are ignored; only a newer disconnect scrubs the number. Use this on warm lists, with the date per contact from step 3 of the lifecycle.
MESSAGING_NUMBER_DEACTIVATED (422) and OTP
with VERIFY_NUMBER_DEACTIVATED (422) — that is the gate working, not a
provider error. The resolution is the reverify leg above: drop the
destination, re-establish a relationship, and let a dated consent postdate
the last_deactivation_date. Retrying the same send against the same
verdict never clears the block.
4. Avoid suppression-ledger side effects
A deactivation verdict is not an opt-out. Writingdeactivated
contacts into the suppression ledger as if they were STOP replies mixes
two different ledgers with two different recovery paths:
- The suppression ledger encodes a person’s instruction — STOP, unsubscribe, complaint — and is a hard send-gate with its own audit semantics and reversal rules.
- The deactivation feed encodes a carrier’s network event. Its recovery is reverification + a newer consent date, not an unsuppress.
should_scrub: true rows to your contact-status
field (for example carrier_deactivated with the
last_deactivation_date), and let suppression stay reserved for genuine
opt-outs. That separation also keeps a bulk import of “recycled numbers”
from polluting the ledger your opt-out audit reads — with false positives
an auditor later has to explain away. If a deactivated subscriber also
opts out on the new relationship, that STOP enters suppression through
the normal keyword path — one ledger per truth.
5. Verify the integration
Run this checklist before you rely on the gate. None of it sends a message, so none of it consumes campaign coverage:- Settings round-trip.
GET /deactivations/settingsreturns your opt-in and a livefeed_synced; on the SaaS platform the feed is synced centrally — iffeed_syncedis false, stop and treat every verdict asno_datauntil it flips. - Known-unknown probe. Check a number you have no history with,
without
last_seen. Expect a well-formed verdict (deactivated,active, orno_data) and ashould_scrubthat equalsstatus === "deactivated"— never an error. - Batch page-through. Scrub a slice of a real audience, confirm
checkedequals your page size andscrub_count + kept_countreconciles. Verify your drop list is exactly theshould_scrub: truerows. - Send-path proof with one live send. Send a single SMS to a contact
you know is deactivated (from your own sweep). Expect a 422 with
MESSAGING_NUMBER_DEACTIVATEDand a written audit entry. That single deliberate refusal proves the guard fires — do not instrument this with bulk traffic. - Lifecycle reload. Record a fresh consent dated after the
last_deactivation_date, re-check with the newlast_seen, and confirm the verdict flips toactive.
6. Failure-mode codes
For the full row set see Error Codes and
Messaging pre-send gates.
See also:
- Carrier Deactivation Scrub — the reference page: field matrix, send-path guard semantics, fail-open caveat.
- Send Gates — how the deactivation guard layers with quiet hours, DNC, RND, and suppression at send time.
- Opt-Out & Suppression Lists — the ledger this runbook deliberately keeps deactivation verdicts out of.
- RND Safe-Harbor Pre-Contact Number Scrubbing — the consent-date safe-harbor check that complements the carrier churn feed.
- DNC preflight scrub — the registry-side pre-flight that answers the orthogonal “did the person ask to stop?” question.