Skip to main content

Worked request and response samples

Copy a request as written, substitute your own values, and compare the response envelope. The policy is one object per organization — the guard that silently drops a send when the identical message body was already delivered to the same recipient on the same channel within window_seconds. Restrict applies_to_categories to marketing copy so OTP and transactional resends are never suppressed. The full lifecycle an operator runs: inspect → upsert → delete to disable.

Where this resource fits

Three mechanisms in Orbit answer to “suppression”, and a reader landing here usually wants one of the other two. This page covers only the organization’s duplicate-content policy — GET, PUT, DELETE on /api/v1/message-suppression — with no per-recipient add/remove/check and no bulk import: suppression here is an organizational toggle over the send path, not an address list.
  • Per-recipient opt-outs and block lists — whether an address is allowed to receive a send at all — flow through consent records and opt-out entries; see the recipient-state model and the opt-out lists keyword surface.
  • Pre-send “is this number blocked” pre-flight — probe GET /compliance/dnc/check (batch counterpart POST /compliance/dnc/scrub) for the send-path verdict across every Do-Not-Call source, scoped by jurisdiction.
  • This page’s policy — deduplication of identical bodies within the window. The send path enforces it inline; there is no per-address status endpoint to poll.
The message-suppression model walks all three mechanisms and tells them apart.

1. Inspect the current policy

GET /api/v1/message-suppression
Request
Read the policy before updating or deleting it. When no policy has ever been configured for the organization, data comes back null — branch on that, not on an error.

2. Create or update the policy

PUT /api/v1/message-suppression
The upsert body: window_seconds (3600–7776000), optional enabled (defaults to true), and optional channels / applies_to_categories (null or omitted = every channel / every category). Writes require an owner, admin, or developer role. Request
Once a policy is live, the send path drops the duplicate and reports it on the message’s delivery status — there is no separate per-address check to call. Omit channels to cover every outbound messaging channel, and keep the category list scoped to marketing copy so OTP and transactional resends are never suppressed.

3. Delete the policy (204)

DELETE /api/v1/message-suppression
Request
Response: 204 No Content Deletion disables suppression immediately — identical messages are no longer dropped — while any per-content markers already recorded in the window expire with their TTL. The endpoint returns 204 whether or not a policy existed, so a delete retried after a timeout is safe. To turn the guard back on, upsert again as in step 2.

Error envelopes worth branching on

Every failure arrives in the same { error, meta } envelope your client branches on. For the platform-wide decision table these plug into, see the error handling guide.

401 — Unauthorized

A 401 is the bearer key failing before the route ran — it never means the policy state is wrong. Rotate the key; retrying the same request changes nothing.

403 — Forbidden

Write calls (PUT, DELETE) require an owner, admin, or developer role; a 403 means the key authenticated but the operation is gated by scope. Fix the key’s role set — a retry with the same key never heals it.

422 — Validation on the upsert body

The two validation failures an upsert body can hit are a window_seconds outside 3600–7776000 and a category string over 64 characters. Branch on error.details.field and resend with a corrected body instead of blind-retrying.

429 — Rate limited

The Retry-After header and error.details.retry_after are both set on every 429 — resend the same request after the lower of the two. There is no 404 on this page: the resource is the organization itself, and an unconfigured policy returns data: null, not an error.

60-second retry matrix