Telnyx Email Unsubscribe Groups API

Named groups and group-scoped suppressions.

Operations 8

GET /email_unsubscribe_groups List unsubscribe groups #
POST /email_unsubscribe_groups Create an unsubscribe group #
DELETE /email_unsubscribe_groups/{id} Delete an unsubscribe group #
GET /email_unsubscribe_groups/{id} Retrieve an unsubscribe group #
PATCH /email_unsubscribe_groups/{id} Update an unsubscribe group #
GET /email_unsubscribe_groups/{id}/suppressions List suppressions in a group #
POST /email_unsubscribe_groups/{id}/suppressions Add a group suppression #
DELETE /email_unsubscribe_groups/{id}/suppressions/{email} Remove a group suppression #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/telnyx:telnyx-email-unsubscribe-groups-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

telnyx-email-unsubscribe-groups-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  version: 2.0.0
  x-latency-category: responsive
  x-endpoint-cost: light
  title: Telnyx Email Unsubscribe Groups API
  description: SIP trunking, SMS, MMS, Call Control and Telephony Data Services.
  contact:
    email: support@telnyx.com
servers:
- url: https://api.telnyx.com/v2
  description: Version 2.0.0 of the Telnyx API
security:
- bearerAuth: []
tags:
- name: Email Unsubscribe Groups
  description: Named groups and group-scoped suppressions.
paths:
  /email_unsubscribe_groups:
    get:
      tags:
      - Email Unsubscribe Groups
      summary: List unsubscribe groups
      description: 'Offset pagination only (`page[number]` default 1, `page[size]`

        default 25, max 100). No `sort`/`filter`/cursor — ordering fixed

        `desc created_at, desc id`. Uses the shared `QueryParser.parse_offset/1`

        — a malformed `page` (e.g. flat `?page=1` instead of

        `?page[number]=1`) returns `400` (code `10015`), consistent with

        `GET /v2/email_blocks`. `meta` includes `total_pages`.'
      operationId: listUnsubscribeGroups
      parameters:
      - $ref: '#/components/parameters/BlocksPageNumber'
      - $ref: '#/components/parameters/BlocksPageSize'
      responses:
        '200':
          description: Groups.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnsubscribeGroupListResponse'
              example:
                data:
                - id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_unsubscribe_group
                  name: string
                  description: string
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
                meta:
                  page_number: 0
                  page_size: 0
                  total_pages: 0
                  total_results: 0
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '406':
          $ref: '#/components/responses/FrameworkError'
    post:
      tags:
      - Email Unsubscribe Groups
      summary: Create an unsubscribe group
      operationId: createUnsubscribeGroup
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUnsubscribeGroupRequest'
            example:
              name: Marketing Newsletter
              description: Weekly product updates and promotions
      responses:
        '201':
          description: Created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnsubscribeGroupResponse'
              example:
                data:
                  id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_unsubscribe_group
                  name: string
                  description: string
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '406':
          $ref: '#/components/responses/FrameworkError'
        '422':
          $ref: '#/components/responses/ChangesetError'
      description: Creates an account-owned unsubscribe group for associating email categories with separate recipient suppression lists.
  /email_unsubscribe_groups/{id}:
    parameters:
    - $ref: '#/components/parameters/PathId'
    delete:
      tags:
      - Email Unsubscribe Groups
      summary: Delete an unsubscribe group
      description: 'If the group has 0 active suppressions, hard-deletes the row. With

        `force=true`, soft-deletes all active suppressions first (status →

        `removed`, `group_id` cleared, `removed` audit event per block) in a

        single transaction, then hard-deletes the group. Without `force`

        and active suppressions present → `409`. Audit trail is preserved.

        `force` only accepts the string `"true"` or boolean `true`; all other

        values are false.'
      operationId: deleteUnsubscribeGroup
      parameters:
      - $ref: '#/components/parameters/ForceQuery'
      responses:
        '204':
          description: Deleted.
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '404':
          $ref: '#/components/responses/BlocksNotFound'
        '406':
          $ref: '#/components/responses/FrameworkError'
        '409':
          description: Group has active suppressions and `force` is false.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorList'
              example:
                errors:
                - code: '40901'
                  title: Conflict
                  detail: Group has 3 active suppression(s). Remove them first or use ?force=true.
        '422':
          $ref: '#/components/responses/ChangesetError'
    get:
      tags:
      - Email Unsubscribe Groups
      summary: Retrieve an unsubscribe group
      operationId: showUnsubscribeGroup
      responses:
        '200':
          description: The group.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnsubscribeGroupResponse'
              example:
                data:
                  id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_unsubscribe_group
                  name: string
                  description: string
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '404':
          $ref: '#/components/responses/BlocksNotFound'
        '406':
          $ref: '#/components/responses/FrameworkError'
      description: Returns the account-owned unsubscribe group identified by ID.
    patch:
      tags:
      - Email Unsubscribe Groups
      summary: Update an unsubscribe group
      description: Partial update (only `name` / `description`). `PUT` is not routed.
      operationId: updateUnsubscribeGroup
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUnsubscribeGroupRequest'
            example:
              description: Weekly product updates and promotions
      responses:
        '200':
          description: The updated group.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnsubscribeGroupResponse'
              example:
                data:
                  id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_unsubscribe_group
                  name: string
                  description: string
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '404':
          $ref: '#/components/responses/BlocksNotFound'
        '406':
          $ref: '#/components/responses/FrameworkError'
        '422':
          $ref: '#/components/responses/ChangesetError'
  /email_unsubscribe_groups/{id}/suppressions:
    parameters:
    - $ref: '#/components/parameters/PathId'
    get:
      tags:
      - Email Unsubscribe Groups
      summary: List suppressions in a group
      description: 'Account + group scoped. Offset pagination only (`page[number]`

        default 1, `page[size]` default 25, max 100). No `sort`/`filter`/

        cursor — ordering fixed `desc created_at, desc id`. Uses the shared

        `QueryParser.parse_offset/1` — a malformed `page` returns `400`

        (code `10015`), consistent with `GET /v2/email_blocks`. `meta`

        includes `total_pages`. Rows reuse the standard suppression shape

        (`group_id` set to this group).'
      operationId: listGroupSuppressions
      parameters:
      - $ref: '#/components/parameters/BlocksPageNumber'
      - $ref: '#/components/parameters/BlocksPageSize'
      responses:
        '200':
          description: Group suppressions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupSuppressionListResponse'
              example:
                data:
                - id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_block
                  domain_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  group_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  from: string
                  to: string
                  reason: hard_bounce
                  source: feedback
                  scope: account
                  status: active
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
                  expires_at: '2024-01-23T18:10:02.574Z'
                meta:
                  page_number: 0
                  page_size: 0
                  total_pages: 0
                  total_results: 0
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '404':
          $ref: '#/components/responses/BlocksNotFound'
        '406':
          $ref: '#/components/responses/FrameworkError'
    post:
      tags:
      - Email Unsubscribe Groups
      summary: Add a group suppression
      description: 'Creates a suppression with `reason: unsubscribe`, `source: manual`,

        `group_id: `. All other body fields are ignored; only

        `to` is read. Idempotent (same dedupe key → `200`, no new event).'
      operationId: addGroupSuppression
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddGroupSuppressionRequest'
            example:
              to: user@example.com
      responses:
        '200':
          description: Idempotent — already existed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmailBlockResponse'
              example:
                data:
                  id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_block
                  domain_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  group_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  from: string
                  to: string
                  reason: hard_bounce
                  source: feedback
                  scope: account
                  status: active
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
                  expires_at: '2024-01-23T18:10:02.574Z'
        '201':
          description: Created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmailBlockResponse'
              example:
                data:
                  id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  record_type: email_block
                  domain_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  group_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                  from: string
                  to: string
                  reason: hard_bounce
                  source: feedback
                  scope: account
                  status: active
                  created_at: '2024-01-23T18:10:02.574Z'
                  updated_at: '2024-01-23T18:10:02.574Z'
                  expires_at: '2024-01-23T18:10:02.574Z'
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '404':
          $ref: '#/components/responses/BlocksNotFound'
        '406':
          $ref: '#/components/responses/FrameworkError'
        '422':
          $ref: '#/components/responses/ChangesetError'
  /email_unsubscribe_groups/{id}/suppressions/{email}:
    parameters:
    - $ref: '#/components/parameters/PathId'
    - $ref: '#/components/parameters/PathEmail'
    delete:
      tags:
      - Email Unsubscribe Groups
      summary: Remove a group suppression
      description: 'Soft-deletes all active blocks for (account, group, normalized

        email) — one `removed` audit event per block (`actor: manual`).

        The `email` path segment is normalized (trim + lower-case) before

        matching. Idempotent on already-removed rows (returns `404` since

        they''re no longer `active`).


        Two distinct `404` cases: a missing/cross-account **group** returns

        `10001 "The requested unsubscribe group was not found"`; a group that

        exists but has **no active suppression** for that email returns

        `10001 "The requested group suppression was not found"`.'
      operationId: removeGroupSuppression
      responses:
        '204':
          description: Removed.
        '401':
          $ref: '#/components/responses/email_Unauthorized'
        '404':
          $ref: '#/components/responses/BlocksNotFound'
        '406':
          $ref: '#/components/responses/FrameworkError'
        '422':
          $ref: '#/components/responses/ChangesetError'
components:
  schemas:
    AddGroupSuppressionRequest:
      type: object
      required:
      - to
      properties:
        to:
          type: string
      description: 'Only `to` is read; all other fields are ignored (`reason: unsubscribe`, `source: manual`, `group_id: <group>` are forced).'
    EmailBlock:
      type: object
      required:
      - id
      - record_type
      - to
      - reason
      - source
      - scope
      - status
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
        record_type:
          type: string
          enum:
          - email_block
          description: View-only discriminator.
        domain_id:
          type: string
          format: uuid
          nullable: true
          description: '`null` ⇒ account scope. Stored on the row; exposed here.'
        group_id:
          type: string
          format: uuid
          nullable: true
          description: '`null` ⇒ global; set ⇒ group-scoped opt-out.'
        from:
          type: string
          nullable: true
          description: '`null` ⇒ not address-scope. (schema: from_address)'
        to:
          type: string
          description: 'Normalized recipient. (schema: to_address)'
        reason:
          $ref: '#/components/schemas/Reason'
        source:
          $ref: '#/components/schemas/email_Source'
        scope:
          $ref: '#/components/schemas/Scope'
        status:
          $ref: '#/components/schemas/Status'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: 'Optional expiration time. An active row stops matching

            send-time suppression checks as soon as `expires_at <= now()`.

            A maintenance worker later transitions the row to `status: expired`

            and appends an `expired` audit event (normally within 15 minutes).

            '
      description: 'Suppression record. Schema fields hidden by the view:

        `account_id`, `bounce_category`, `dsn_code`, `meta`.

        '
    UnsubscribeGroupListResponse:
      type: object
      required:
      - data
      - meta
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/UnsubscribeGroup'
        meta:
          $ref: '#/components/schemas/GroupListMeta'
    GroupSuppressionListResponse:
      type: object
      required:
      - data
      - meta
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/EmailBlock'
        meta:
          $ref: '#/components/schemas/GroupListMeta'
    UnsubscribeGroup:
      type: object
      required:
      - id
      - record_type
      - name
      - description
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
        record_type:
          type: string
          enum:
          - email_unsubscribe_group
          description: View-only.
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          nullable: true
          description: Always present (not omit-nullable); `null` when unset.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    CreateUnsubscribeGroupRequest:
      type: object
      required:
      - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          nullable: true
    email_Source:
      type: string
      enum:
      - feedback
      - manual
      - import
      - system
    UnsubscribeGroupResponse:
      type: object
      required:
      - data
      properties:
        data:
          $ref: '#/components/schemas/UnsubscribeGroup'
    EmailBlockResponse:
      type: object
      required:
      - data
      properties:
        data:
          $ref: '#/components/schemas/EmailBlock'
    UpdateUnsubscribeGroupRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          nullable: true
      description: Partial update; `account_id`/`id` are immutable.
    Reason:
      type: string
      enum:
      - hard_bounce
      - spam_complaint
      - unsubscribe
      - invalid
      - manual_block
    ErrorList:
      type: object
      required:
      - errors
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/BlocksErrorObject'
    BlocksErrorObject:
      type: object
      required:
      - code
      - title
      - detail
      properties:
        code:
          type: string
          description: 'Error codes: `10001` (Not Found), `10007` (Unauthorized),

            `10015` (Validation Failed), `10019` (Internal — import create

            fallback), `40901` (Conflict), `500` (framework/catch-all).

            '
        title:
          type: string
        detail:
          type: string
        source:
          type: object
          properties:
            pointer:
              type: string
          description: '`/data/attributes/<field>` for changeset/Params; `/<field>` for query-param errors.'
    Scope:
      type: string
      enum:
      - account
      - domain
      - address
      description: Derived server-side from `domain_id`/`from`; never trusted from the caller.
    Status:
      type: string
      enum:
      - active
      - expired
      - removed
    GroupListMeta:
      type: object
      required:
      - page_number
      - page_size
      - total_pages
      - total_results
      description: Group list `meta` (consistent with `GET /v2/email_blocks`).
      properties:
        page_number:
          type: integer
        page_size:
          type: integer
        total_pages:
          type: integer
        total_results:
          type: integer
  responses:
    BlocksNotFound:
      description: Resource not found (cross-account lookups and malformed UUIDs also return 404 — no leak).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorList'
          example:
            errors:
            - code: '10001'
              title: Not Found
              detail: The requested email block was not found
    FrameworkError:
      description: '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.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorList'
          example:
            errors:
            - code: '406'
              title: Not Acceptable
              detail: Not Acceptable
    ChangesetError:
      description: Validation error (changeset or internal `Params`). One error object per field, `source.pointer /data/attributes/<field>`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorList'
          example:
            errors:
            - code: '10015'
              title: Validation Failed
              detail: can't be blank
              source:
                pointer: /data/attributes/to
    email_Unauthorized:
      description: Missing or invalid gateway auth.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorList'
          example:
            errors:
            - code: '10007'
              title: Unauthorized
              detail: Missing authentication
  parameters:
    BlocksPageNumber:
      name: page[number]
      in: query
      description: Offset page number (≥1, default 1).
      schema:
        type: integer
        minimum: 1
        default: 1
    PathId:
      name: id
      in: path
      required: true
      description: Resource UUID. Malformed UUIDs are treated as not-found (not 400).
      schema:
        type: string
        format: uuid
    BlocksPageSize:
      name: page[size]
      in: query
      description: Page size (1–100, default 25).
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    PathEmail:
      name: email
      in: path
      required: true
      description: 'Recipient address (normalized: trim + lower-case before matching).'
      schema:
        type: string
    ForceQuery:
      name: force
      in: query
      description: Force-delete a group with active suppressions. Only `"true"` (string) or `true` (bool) are truthy; all other values are false.
      schema:
        oneOf:
        - type: string
          enum:
          - 'true'
          - 'false'
        - type: boolean
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Telnyx API key supplied as `Authorization: Bearer <token>`. In production, auth may be validated by the API gateway and forwarded via Telnyx auth headers.'
    Payment:
      type: apiKey
      in: header
      name: Authorization
      description: 'Machine Payment Protocol credential used on paid retries, sent as `Authorization: Payment ...`. Obtained by paying a challenge returned in the `WWW-Authenticate` header of a 402 response. This is not a Telnyx API key; initial challenge requests use standard bearer authentication instead.'
    agent-memory_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API key
    bearerAuth:
      type: http
      scheme: bearer
    branded-calling_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API key. Generate one at https://portal.telnyx.com/#/app/api-keys.
    collections_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API key. Collections and results are automatically scoped to the authenticated user's organization.
    number-reputation_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API key. Generate one at https://portal.telnyx.com/#/app/api-keys.
    oauthClientAuth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://api.telnyx.com/v2/oauth/token
          scopes:
            admin: Administrative access to Telnyx resources
        authorizationCode:
          authorizationUrl: https://api.telnyx.com/v2/oauth/authorize
          tokenUrl: https://api.telnyx.com/v2/oauth/token
          refreshUrl: https://api.telnyx.com/v2/oauth/token
          scopes:
            admin: Administrative access to Telnyx resources
      description: OAuth 2.0 authentication for Telnyx API and MCP integrations
    outbound-voice-profiles_bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    pronunciation-dicts_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API v2 key. Obtain from https://portal.telnyx.com
    rcs-registration_bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
    stored-payment-transactions_bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    transcriptions-search_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API key. Results are automatically scoped to the authenticated user's organization.
    web-search_bearerAuth:
      type: http
      scheme: bearer
      description: Telnyx API key
x-service-info:
  categories:
  - communication
  - developer-tools
  docs:
    apiReference: https://developers.telnyx.com
    homepage: https://telnyx.com
    llms: https://telnyx.com/llms.txt