Suppressions
A suppression is an account-wide “never email this address” entry. One entry
blocks the address in every audience and on transactional sends. It outranks a
contact’s status, a campaign’s targeting, and a POST /emails.
Moving from another provider? Import its suppression list before your first send. Otherwise your first campaign re-mails every address that already bounced or complained elsewhere, and receiving providers notice.
The Suppression object
{
"id": "sup_9x4v0dz1k2m7",
"object": "suppression",
"email": "bounced@example.com",
"reason": "bounced",
"source": "api:key_2v0dz1k9x4m",
"created_at": "2026-08-10T12:00:00.000Z"
}reason | Meaning | Writable over the API |
|---|---|---|
unsubscribed | Opted out. | Yes |
bounced | Hard bounce. | Yes |
complained | Marked as spam. | Yes |
manual | Added by hand in the app. | No |
provider_suppressed | Suppressed by the mail provider. | No |
source is app for the UI or api:<key id> for an API write, so a bad import
can be traced to its key.
List suppressions
/v1/suppressionsYour account’s own entries, newest first, cursor-paginated.
curl "https://go.day3.app/api/v1/suppressions?limit=100" \
-H "Authorization: Bearer $DAY3_API_KEY"Check one address
/v1/suppressions/{email}200 with the entry if suppressed, 404 if not. URL-encode the email. Use it
to find out why a batch item failed with email_suppressed.
curl https://go.day3.app/api/v1/suppressions/bounced%40example.com \
-H "Authorization: Bearer $DAY3_API_KEY"This check also consults day3’s global suppression entries, so it can return
200 for an address that is not in your list.
Add suppressions
/v1/suppressions| Field | Type | Required | Notes |
|---|---|---|---|
reason | string | Yes | unsubscribed, bounced or complained. No default, so every entry is attributable. |
emails | string[] | Yes | Up to 1,000 per call. |
curl -X POST https://go.day3.app/api/v1/suppressions \
-H "Authorization: Bearer $DAY3_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: suppression-import-1" \
-d '{
"reason": "bounced",
"emails": ["a@x.com", "b@y.com"]
}'The response shows the blast radius:
{
"added": 950,
"already_suppressed": 45,
"invalid": 5,
"total_suppressed_before": 200,
"total_suppressed_after": 1150
}The API’s biggest foot-gun. Post a full contact export instead of a suppression
export and your whole audience becomes unmailable, silently. Check
total_suppressed_after against what you expected.
Idempotency-Key is supported. Set it on imports.
There is no delete
API writes are add-only. There is no DELETE /v1/suppressions/{email}.
Un-suppress in the app, per address, under Audiences then Suppressions, with reason and source visible. A scripting mistake stays recoverable but cannot be bulk-reverted by script, and a leaked key cannot un-suppress bounced addresses to force-mail them.
Un-suppressing restores contacts marked bounced, complained or suppressed
to subscribed. Self-service unsubscribes stay unsubscribed.
Interaction with contacts
Suppressing an address does not delete contact rows; they become
unmailable. Creating a contact for a suppressed address returns
409 email_suppressed.
Import suppressions before contacts, and expect those rows to fail on the way in. That is correct, not something to retry. See Migrate a list.
Interaction with transactional email
- An unsubscribe does not block a transactional send. A newsletter opt-out must never stop a password reset.
- A bounce, complaint or provider suppression does, with
400 email_suppressed.
See Emails.