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

# Message Suppression API

> Skip a send when the identical message body already reached the same contact on the same channel inside a rolling window. One opt-in, content-hash duplicate-suppression policy per organization, enforced inside the message send pipeline.

# Message Suppression API

Configure content-hash duplicate suppression: a send is silently skipped when the **same message body** already reached the **same contact** on the **same channel** inside a window you choose. This is the "two different campaigns fired the identical promo back-to-back" guard — distinct from [frequency caps](/api-reference/frequency-caps) (which count send *firings* per contact) and [opt-outs](/api-reference/optouts) (which block a channel entirely).

Enforcement happens inside the message send pipeline, before frequency capping, so a duplicate never burns a cap slot. A suppressed send reports as **skipped** (reason `duplicate_content`) rather than an error, so campaigns and batches keep moving.

**Base path:** `/api/v1/message-suppression`

**Authentication:** API key (`X-API-Key`) or session JWT. Reads require any role; the upsert and delete writes require `owner`, `admin`, or `developer`.

| Method   | Path                           | Purpose                                                |
| -------- | ------------------------------ | ------------------------------------------------------ |
| `GET`    | `/api/v1/message-suppression/` | Read the org's policy (`null` when none is configured) |
| `PUT`    | `/api/v1/message-suppression/` | Create or update the policy                            |
| `DELETE` | `/api/v1/message-suppression/` | Turn suppression off (delete the policy)               |

## Policy shape

A single opt-in policy per organization.

| Field                   | Type               | Notes                                                                                                                                                     |
| ----------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`               | `boolean`          | Defaults to `true`. A bare `PUT` with a window turns the policy on.                                                                                       |
| `window_seconds`        | `integer`          | How long a delivered body is remembered. Bounds: `3600` (1 hour) … `7776000` (90 days).                                                                   |
| `channels`              | `string[] \| null` | `null` / omitted = every channel. A populated list restricts the policy to those channels (same channel set as frequency caps).                           |
| `applies_to_categories` | `string[] \| null` | `null` / omitted = every category. Populate with e.g. `["marketing"]` so one-time passcodes, receipts, and other transactional sends are never held back. |
| `updated_at`            | `string`           | Read-only ISO-8601 timestamp of the last change.                                                                                                          |

## Example — dedupe marketing sends within 7 days

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/message-suppression/ \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "window_seconds": 604800,
    "channels": ["sms", "whatsapp"],
    "applies_to_categories": ["marketing"]
  }'
```

Restricting `applies_to_categories` to marketing means OTP and transactional resends are never suppressed. Omit `channels` (or send `null`) to cover every messaging channel.

<Note>
  Suppression **fails open**: if no policy applies, or the backing store is briefly unavailable, the send is dispatched normally — a transient blip never silently swallows outbound traffic. Bodies are compared by SHA-256 of the whitespace-normalized text, so cosmetically-identical copy (reflowed spacing) collapses to the same marker while different case or wording does not.
</Note>

## See also

* [Frequency Caps API](/api-reference/frequency-caps) — rolling-window send limits per contact; enforced alongside suppression.
* [Opt-outs API](/api-reference/optouts) — hard channel-level opt-out, enforced regardless of suppression or caps.
* [Compliance → opt-out & suppression](/compliance/opt-out-suppression)
