Suppressions API

A suppressed address is one Broadcast will not email. Bounces and complaints add addresses automatically, and you can manage the lists yourself through the API.

There are two lists, and they are separate resources:

  • Channel suppressions/api/v1/suppressions. Blocks the address for one channel. The same person can still be emailed from your other channels.
  • Global suppressions/api/v1/global_suppressions. Blocks the address across every channel you have access to.

An address may appear on both. Nothing is sent to an address on either list.

Which one do I want?

If an address bounced or complained in one channel and you never want to email that person again from anywhere, use the global list. That is the usual answer when you are importing bad addresses from another platform, where the bounce history did not come across with the contacts.

Use the channel list when the block is specific to one brand or audience — someone who unsubscribed from one newsletter but is a legitimate contact for another.

Required Permissions

All endpoints require an API token with suppression permissions:

  • Read: GET endpoints, including the check endpoint
  • Write: POST and DELETE endpoints

Warning

The global endpoints require an admin API token. A channel-scoped token can read and write only its own channel’s list. This is deliberate: the global list affects every channel on the installation, so a channel token that could write to it would reach far beyond the channel it was issued for.

Admin API tokens must send broadcast_channel_id on the channel endpoints, as they do everywhere else in the API. They must not send it on the global endpoints — a global suppression does not belong to a channel.

Creating either kind of token, and the request rate limits that apply to all API calls, are covered in API Authentication.

The Suppression Object

Field Description
`id` Unique identifier of the suppression
`email` The suppressed address, always lowercased and trimmed
`scope` `channel` or `global`
`broadcast_channel_id` The channel it applies to, or `null` for a global suppression
`created_at` When the address was suppressed

Addresses are normalised before they are stored and before they are compared, so Bob@Example.COM and bob@example.com are the same address throughout.

Suppressing an address does not change the subscriber record. The subscriber stays active and stays in your counts; the address is simply skipped at send time. Suppression is separate from unsubscribing — an unsubscribe is the subscriber’s own decision and is recorded against them, while a suppression is yours.

Check an Address

GET /api/v1/suppressions/check

Answers the question most integrations actually need: will this address receive mail? It checks the global list first, then this channel’s list, and tells you which one matched.

Use this rather than fetching both lists and comparing them yourself. An address blocked globally will not receive mail even though it appears nowhere in your channel’s list.

Query Parameters

  • email (required): the address to check

Request

curl -X GET \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  "http://your-domain.com/api/v1/suppressions/check?email=bob@example.com"

Response

{
  "email": "bob@example.com",
  "suppressed": true,
  "scope": "global"
}

scope is global or channel when suppressed is true, and null when it is false:

{
  "email": "alice@example.com",
  "suppressed": false,
  "scope": null
}

This endpoint needs only read permission on a channel token. It reports one address; it does not let a channel token browse the global list.

Check is channel-scoped, so an admin API token must name the channel it is asking about — the same broadcast_channel_id the other channel endpoints take:

curl -X GET \
  -H "Authorization: Bearer YOUR_ADMIN_API_TOKEN" \
  "http://your-domain.com/api/v1/suppressions/check?email=bob@example.com&broadcast_channel_id=1"

List Channel Suppressions

GET /api/v1/suppressions

Returns a paginated list of addresses suppressed for this channel. Global suppressions are not included — use the global endpoint for those, or the check endpoint for a single address.

Query Parameters

  • page: Page number (default: 1)
  • email: Filter to addresses containing this text

Request

curl -X GET \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  http://your-domain.com/api/v1/suppressions

Response

{
  "suppressions": [
    {
      "id": 42,
      "email": "bob@example.com",
      "scope": "channel",
      "broadcast_channel_id": 1,
      "created_at": "2026-07-30T12:34:56Z"
    }
  ],
  "pagination": {
    "total": 1,
    "count": 1,
    "from": 1,
    "to": 1,
    "current": 1,
    "total_pages": 1
  }
}

Add a Channel Suppression

POST /api/v1/suppressions

Adds one address to this channel’s list.

Parameters

  • email (required): the address to suppress

Request

curl -X POST \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "email": "bob@example.com" }' \
  http://your-domain.com/api/v1/suppressions

Response

{
  "id": 42,
  "email": "bob@example.com",
  "scope": "channel",
  "broadcast_channel_id": 1,
  "created_at": "2026-07-30T12:34:56Z"
}

Adding an address that is already suppressed succeeds and returns the existing record. It is not an error, so you do not need to check before adding. A newly created suppression answers 201; one that was already there answers 200, so you can still tell the two apart if it matters.

Bulk Add Channel Suppressions

POST /api/v1/suppressions/bulk

Adds up to 10,000 addresses in one request, all to this channel’s list.

If you are importing bounce and complaint history from another platform, you almost certainly want the global list instead — see Importing from another platform below.

Parameters

  • emails (required): an array of addresses

Request

curl -X POST \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": [
      "bob@example.com",
      "carol@example.com",
      "not-an-email"
    ]
  }' \
  http://your-domain.com/api/v1/suppressions/bulk

Response

{
  "added": 2,
  "already_suppressed": 0,
  "invalid": ["not-an-email"]
}

Every address is accounted for:

  • added — newly suppressed
  • already_suppressed — on the list before this request
  • invalid — could not be read as an email address, and were skipped

One malformed address does not fail the request. The rest are still added, and the bad one comes back in invalid so you can correct your source data.

Duplicates inside a single request count once. Sending the same batch twice adds nothing the second time, so a retry after a network timeout is safe.

Warning

More than 10,000 addresses in one request is rejected with 422. Split larger imports into batches.

Remove a Channel Suppression

DELETE /api/v1/suppressions

Removes an address from this channel’s list. A global suppression for the same address is left in place, so the address may still be blocked — check with the check endpoint if you expect mail to start flowing again.

Query Parameters

  • email (required): the address to remove

Request

curl -X DELETE \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  "http://your-domain.com/api/v1/suppressions?email=bob@example.com"

Response

{
  "email": "bob@example.com",
  "removed": true
}

Removing an address that was not suppressed returns "removed": false with a 200. It is not an error.

Bulk Remove Channel Suppressions

DELETE /api/v1/suppressions/bulk

Removes up to 10,000 addresses from this channel’s list in one request. The counterpart to bulk add — if an import used the wrong file, this is how you undo it without one request per address.

Parameters

  • emails (required): an array of addresses

Request

curl -X DELETE \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "emails": ["bob@example.com", "carol@example.com"] }' \
  http://your-domain.com/api/v1/suppressions/bulk

Response

{
  "removed": 2,
  "not_found": 0
}

Addresses that were not suppressed are counted in not_found rather than failing the request, so re-running the same removal is safe.

Global Suppressions

The global endpoints mirror the channel ones exactly and take the same parameters. They require an admin API token, and must not be given a broadcast_channel_id.

GET    /api/v1/global_suppressions            list, paginated
POST   /api/v1/global_suppressions            add one
POST   /api/v1/global_suppressions/bulk       add up to 10,000
DELETE /api/v1/global_suppressions?email=     remove one
DELETE /api/v1/global_suppressions/bulk       remove up to 10,000

Add One

curl -X POST \
  -H "Authorization: Bearer YOUR_ADMIN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "email": "bob@example.com" }' \
  http://your-domain.com/api/v1/global_suppressions
{
  "id": 77,
  "email": "bob@example.com",
  "scope": "global",
  "broadcast_channel_id": null,
  "created_at": "2026-07-30T12:34:56Z"
}

Add in Bulk

curl -X POST \
  -H "Authorization: Bearer YOUR_ADMIN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": [
      "bob@example.com",
      "carol@example.com",
      "not-an-email"
    ]
  }' \
  http://your-domain.com/api/v1/global_suppressions/bulk
{
  "added": 2,
  "already_suppressed": 0,
  "invalid": ["not-an-email"]
}

The same rules as the channel bulk endpoint: one malformed address does not fail the request, duplicates inside a batch count once, and re-sending a batch adds nothing the second time.

Warning

DELETE /api/v1/global_suppressions removes the address from the global list only. Channel suppressions for the same address are left alone, and will keep blocking mail in those channels.

Importing from Another Platform

Moving from another email platform is the case these endpoints were built for. Contacts usually import cleanly while their bounce and complaint history does not, so addresses that platform had already given up on arrive in Broadcast looking perfectly healthy — and get mailed again.

Export the bounced and complained addresses from the old platform, reduce them to a bare list of addresses, and load them into the global list before your first send:

curl -X POST \
  -H "Authorization: Bearer YOUR_ADMIN_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "emails": ["bob@example.com", "carol@example.com"] }' \
  http://your-domain.com/api/v1/global_suppressions/bulk

Global rather than per-channel, because a hard bounce is bad everywhere: the address is dead regardless of which of your channels reaches it next.

More than 10,000 addresses. Split the list into batches of 10,000 or fewer and send them one after another. Every batch reports its own counts, and because re-sending a batch adds nothing you can safely retry one that timed out without tracking which addresses it contained.

Note

API requests are rate limited. Each response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers — read X-RateLimit-Remaining between batches and pause until the reset time rather than retrying blind. See API Authentication for the current limits.

If the addresses you want to block are already on one channel’s list, you do not need the API at all — see Copying a channel’s list to the global list at the end of this page.

Errors

Status Meaning
`400` An admin API token called a channel endpoint without `broadcast_channel_id`
`401` Missing or unrecognised token, the token lacks suppression permission, or a channel token called a global endpoint
`422` `email` or `emails` missing, or a bulk request over 10,000 addresses
`429` Rate limit exceeded — check `X-RateLimit-Reset` and retry after it

Copying a Channel’s List to the Global List

To promote an entire channel’s suppression list in one go, use Channel Maintenance in the app rather than the API. It previews what would be copied, runs in the background for large lists, and keeps the channel’s own list intact.

Was this page helpful?

Thanks for your feedback!

Thanks for letting us know. We'll work on improving this page.