Message suppression model
Message suppression is the content-hash duplicate guard: a send is silently skipped when the identical body already reached the same contact on the same channel inside a window you choose. It is a safety net against double-sends — not a compliance control, and not the contact block list. Three mechanisms in Orbit all answer to “suppression” and are routinely confused for one another. This page tells them apart: which question each answers, where each sits in the send pipeline, which console and API each lives behind, and which one to reach for.One-line semantic
Suppression list is compliance-owned; message suppression is a safety net; consent suppression is an opt-out gate.
Read the table top-down and the words stop colliding: one is a policy, one is recipient state, one is a ledger. None of the three replaces another.
The three concepts side by side
Duplicate-content suppression — metadata-based, relative suppression of identical bodies. The policy is a single opt-in object per organization. On every send the pipeline hashes the whitespace-normalized body text and claims the(recipient, channel, body-hash) marker as one compare-and-set; an identical body in flight within the window loses and is skipped. Manipulation primitives: GET / PUT / DELETE /api/v1/message-suppression, plus a dashboard wrapper.
Consent suppression — per-channel gate driven by ledger state.
Consent is recorded per contact with a lawful basis, and mirrored into per-channel flags the send path checks. An opt-out writes a fresh consent record, flips the flags, and (for a phone number reaching voice) writes a suppression row — see Consent, opt-out, and suppression. The gate is a refusal, not a skip: direct sends get 422 RECIPIENT_OPTED_OUT; campaign sends to opted-out recipients are skipped at the recipient-list level.
Suppression list — per-row, per-channel, CSV-imported compliance block list.
The same ledger of (address, channel-scope) rows powers both the migrations you bulk-import (POST /compliance/suppression-list/import) and the rows an opt-out writes through its own entry point. Scope defaults (all for phone-type addresses, email for email addresses) and per-row overrides are documented in Opt-Out & Suppression Lists.
Two of these land in the same underlying ledger — that is why the console renders the consent inspector and the import wizard next to each other — while the duplicate-content guard is a separate Redis-backed marker store. “Suppressed” in an audit most often means “blocked by a suppression-list row”; which of the three did the work is recorded on the message outcome and in the recipient’s consent history.
Where each sits in the pipeline
Each outbound send walks the admission chain in a fixed order (the complete chain — wallet posture, quiet hours, throughput — is in Outbound send gating):- Opt-out / compliance gate — consent suppression and the suppression list both land here. A recipient whose flags or ledger rows block the channel is refused first; nothing downstream ever runs for them.
- Duplicate-content suppression — the message-suppression policy this page organizes. Runs only for recipients who cleared the gate, and skips an identical re-body without burning quota.
- Frequency cap — the per-channel count axis (“how many sends in N hours”), consulted only after suppression has had its say; a suppressed duplicate never consumes a cap slot.
- Dispatch — the message is handed to the channel provider.
Why the names collide in the dashboard
The console hosts all three under Settings, and two of them both say “suppression”:- Settings → Message suppression manages the duplicate-content policy — the content-hash guard on this page — as a thin wrapper over the same
GET/PUT/DELETE /api/v1/message-suppressionroute the API exposes. - Settings → Opt-out lists & compliance is the compliance surface: suppression-chain entries and the CSV import/export wizard operate on the suppression list ledger, the second mechanism.
Propose or refuse — choosing the right mechanism
- Propose the suppression list for compliance-owned runbooks: migrating a legacy “never contact” export, onboarding a litigator-scrub file, honouring a partner’s unsubscribe feed. Its import is rate-limited, deduplicated, and dry-run-able; export it back out when legal asks for the ledger.
- Refuse the suppression list for consent-primacy questions. “Why was this contact blocked?” and “under which basis did they opt back in?” are questions about the consent ledger — answer them from consent records and the recipient state, not from CSV rows. Re-messaging a suppressed contact without a documented fresh consent event is what the re-consent semantics exist to prevent.
- Propose message suppression when campaigns, flows, or retry logic can double-fire the same body and you would rather drop the duplicate silently than have a customer receive it twice. Keep it scoped to marketing categories so OTPs and receipts are never held back.
- Refuse message suppression as a substitute for honouring an opt-out. It deduplicates intended sends; it does not block a channel, and a contact who said STOP must be refused at the gate — not kept eligible and occasionally deduped.
See also
- Message suppression guide — operating the duplicate-content policy end-to-end
- Message Suppression API — the policy schema and recipes
- Opt-Out & Suppression Lists — the suppression-list ledger, CSV import/export, and reversal semantics
- Consent, opt-out, and suppression model — the recipient-state stores the opt-out gate reads
- Consent inspector — per-contact consent records and destination verdicts
- Outbound send gating — the full admission-chain ordering
- Opt-outs API — per-channel consent and blocking endpoints