---
title: "Add a group suppression"
method: POST
path: "/email_unsubscribe_groups/{id}/suppressions"
tags: ["Email Unsubscribe Groups"]
---

# Add a group suppression

`POST /email_unsubscribe_groups/{id}/suppressions`

Creates a suppression with `reason: unsubscribe`, `source: manual`,
`group_id: <this group>`. All other body fields are ignored; only
`to` is read. Idempotent (same dedupe key → `200`, no new event).

## Request body

- AddGroupSuppressionRequest — Only `to` is read; all other fields are ignored (`reason: unsubscribe`, `source: manual`, `group_id: <group>` are forced).
  - `to` string, required

## Response `200`

Idempotent — already existed.

- EmailBlockResponse
  - `data` EmailBlock, required — Suppression record. Schema fields hidden by the view: `account_id`, `bounce_category`, `dsn_code`, `meta`.
    - `id` string, uuid, required
    - `record_type` 'email_block', required — View-only discriminator.
    - `domain_id` string, uuid, nullable — `null` ⇒ account scope. Stored on the row; exposed here.
    - `group_id` string, uuid, nullable — `null` ⇒ global; set ⇒ group-scoped opt-out.
    - `from` string, nullable — `null` ⇒ not address-scope. (schema: from_address)
    - `to` string, required — Normalized recipient. (schema: to_address)
    - `reason` 'hard_bounce' | 'spam_complaint' | 'unsubscribe' | 'invalid' | 'manual_block', required
    - `source` 'feedback' | 'manual' | 'import' | 'system', required
    - `scope` 'account' | 'domain' | 'address', required — Derived server-side from `domain_id`/`from`; never trusted from the caller.
    - `status` 'active' | 'expired' | 'removed', required
    - `created_at` string, date-time, required
    - `updated_at` string, date-time, required
    - `expires_at` string, date-time, nullable

## Other responses

- `201` — Created.
- `401` — Missing or invalid gateway auth.
- `404` — Resource not found (cross-account lookups and malformed UUIDs also return 404 — no leak).
- `406` — Framework-rendered error (e.g. 406 Not Acceptable, 405 Method Not Allowed, 415 Unsupported Media Type). HTTP status matches the error and the body `code` carries that same status (e.g. `"406"`, not a hardcoded `"500"`). The explicit `500.json` clause still emits `code: "500"` for genuine 500s.
- `422` — Validation error (changeset or internal `Params`). One error object per field, `source.pointer /data/attributes/<field>`.

---

[API](https://skmtc.net/team-telnyx/apis/telnyx-api-2.md) · [All operations](https://skmtc.net/team-telnyx/apis/telnyx-api-2/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/team-telnyx/telnyx-api-2/versions/8f5f4e537994/schema)
