Documentation

Suppressions

The addresses a workspace refuses to mail, why, and for which kind of mail: look one up, add them singly or in bulk, and lift them.

A suppression stops mail to one address in one workspace. Every send checks the list for each recipient in to, cc and bcc before anything goes out: a single send, a batch, a scheduled send at its due time, each address's turn in a campaign, and each step of an automation. A suppressed recipient is dropped from the message. When no to recipient is left, a direct send returns 202 with skipped: true and is recorded in the log as rejected, so the log can answer "why didn't this arrive?"; a scheduled send in that position is marked canceled when it falls due. See Sending.

When someone reports that they never received an email, look the address up here first with ?email=.

Suppressions are per workspace. One product's unsubscribe never silences another workspace's mail to the same person.

Scopes

Each suppression has a scope that says which mail it blocks, matched against the risk class of the message. A send's risk class is transactional unless the send says marketing; campaigns and automations are always marketing.

ScopeBlocks
allEvery message to the address, transactional and marketing.
transactionalTransactional mail only. Marketing mail still goes out.
marketingMarketing mail only: campaigns, automations and sends marked marketing. Password resets, receipts and other transactional mail still arrive.

An address can hold several suppressions, one per scope, and a message is blocked if any of them covers its risk class.

Reasons

ReasonSet by
hard_bounceSendRaven, when SES reports a permanent bounce, or when a contact is imported with status bounced. Always scope all. Transient bounces (a full mailbox, greylisting) are never suppressed, because they resolve on their own.
complaintSendRaven, when a recipient marks a message as spam, or when a contact is imported with status complained. Always scope all.
unsubscribeSendRaven, with scope marketing so transactional mail keeps arriving: when a recipient uses the unsubscribe-from-everything link or the preference centre's opt-out, when a contact is marked unsubscribed, or when a contact is imported with status unsubscribed. Opting out of a single topic does not create a suppression. You can also set it through this API.
manualYou, through this API or the dashboard. The default for a single add.
list_hygieneYou, typically when importing another provider's suppression list. The default for a batch add.

Only hard bounces and complaints are suppressed with scope all automatically. The reasons hard_bounce and complaint cannot be set through this endpoint; they can arrive through a contact import.

The suppression object

Listing and adding return the same object. Every field is always present.

FieldTypeDescription
idstringUnique identifier (UUID).
emailstringThe address, trimmed and lower-cased.
reason"hard_bounce" | "complaint" | "unsubscribe" | "manual" | "list_hygiene"Why the address is suppressed. See Reasons.
scope"all" | "transactional" | "marketing"Which mail it blocks. See Scopes.
detailstring | nullUp to 500 characters: the SMTP diagnostic for a hard bounce, the feedback type for a complaint, how someone unsubscribed, or the source of an import. null when there is none. Never set by this API.
created_atstring (ISO 8601)When the address was first suppressed with this scope.

List suppressions

GET /v1/suppressions · requires emails:read

Returns suppressions newest first, cursor-paged. See Pagination.

Pass email to answer "is this address blocked, and for what?" directly: the response then holds every suppression that address has, one per scope, and an empty data array means it is not suppressed at all.

Query parameters

ParameterTypeDefaultDescription
emailstringnoneReturn only this address. Matched after trimming and lower-casing.
limitinteger50Page size, at most 100. See Pagination.
cursorstringnoneThe next_cursor from the previous page.

Example

curl "https://api.sendraven.ai/v1/suppressions?email=ana@example.com" \
  -H "Authorization: Bearer $SENDRAVEN_API_KEY"

Response

200 OK

{
  "object": "list",
  "data": [
    {
      "id": "7c2e9a14-5b3d-4f6e-8a1c-2d9b0e7f4a35",
      "email": "ana@example.com",
      "reason": "unsubscribe",
      "scope": "marketing",
      "detail": "one-click unsubscribe",
      "created_at": "2026-09-15T12:00:00.000Z"
    },
    {
      "id": "0f9d8c7b-6a5e-4d3c-2b1a-0e9f8d7c6b5a",
      "email": "ana@example.com",
      "reason": "hard_bounce",
      "scope": "all",
      "detail": "smtp; 550 5.1.1 user unknown",
      "created_at": "2026-09-01T08:30:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Add a suppression

POST /v1/suppressions · requires emails:send

Suppresses one address. It takes effect on the next send: scheduled mail and running campaigns and automations re-check the list at each address's turn.

Adding is idempotent on the address and scope. If the address already has a suppression with this scope, no second row is created: the existing one keeps its id, created_at and detail, and its reason is replaced by the one you send, unless the stored reason is stronger. A hard_bounce or complaint is never replaced by manual, list_hygiene or unsubscribe, so the record of why an address is blocked survives a re-add. The response is the suppression as stored, so its reason is the one that stands. Adding with a narrower scope creates a separate suppression and leaves a broader one in place, still blocking.

With reason unsubscribe, this is an unsubscribe, and it does what an unsubscribe through the link in a message does to the person's queued mail: their pending scheduled sends are cancelled and their active automation enrolments end, whatever the scope. A scheduled send counts as theirs when they are its first to address, and it is cancelled whole, for any other recipients too; one that names them further down is not cancelled, and they are dropped from it when it falls due if the suppression's scope covers it. It does not change their contact record or topic preferences.

Body

FieldTypeRequiredDefaultDescription
emailstringYesnoneA valid email address. Stored trimmed and lower-cased.
reason"manual" | "list_hygiene" | "unsubscribe"No"manual"Why you are suppressing it.
scope"all" | "transactional" | "marketing"No"all"Which mail to block. Use marketing for someone who asked to stop receiving newsletters, so their password resets still arrive.

Example

curl https://api.sendraven.ai/v1/suppressions \
  -X POST \
  -H "Authorization: Bearer $SENDRAVEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "email": "ana@example.com", "reason": "unsubscribe", "scope": "marketing" }'

Response

201 Created

A suppression object, as stored after the write. It is 201 whether or not the address was already suppressed. reason differs from the one you sent when the address already had a stronger reason with this scope, and id, created_at and detail are the existing suppression's when there was one.

{
  "id": "7c2e9a14-5b3d-4f6e-8a1c-2d9b0e7f4a35",
  "email": "ana@example.com",
  "reason": "unsubscribe",
  "scope": "marketing",
  "detail": null,
  "created_at": "2026-09-15T12:00:00.000Z"
}

Errors

StatusTypeWhen
422invalid_requestemail is missing or not a valid address, or reason or scope is not one of the listed values. details lists the problems.

Remove a suppression

DELETE /v1/suppressions/{email} · requires emails:send

Lifts one address's suppression in one scope.

A scope matches exactly. Removing with scope all deletes only an all suppression; an address that also has a marketing suppression stays blocked for marketing mail. Look an address up with ?email= to see every scope it holds.

Removal does not check the reason. Lifting a hard_bounce or complaint suppression re-enables mail to an address the receiving server said does not exist, or to someone who reported spam. Both raise the bounce and complaint rates AWS enforces on, and can get the account's sending paused. Never lift a suppression to work around a failed send.

removed is true when a suppression with that scope existed and was deleted, and false when there was nothing to remove. A false usually means the address is suppressed under a different scope, or not at all; list it with ?email= to see.

Path parameters

ParameterDescription
emailThe address, URL-encoded. Not validated. Matched after trimming and lower-casing.

Query parameters

ParameterTypeDefaultDescription
scope"all" | "transactional" | "marketing""all"The scope of the suppression to remove.

Example

curl "https://api.sendraven.ai/v1/suppressions/ana%40example.com?scope=marketing" \
  -X DELETE \
  -H "Authorization: Bearer $SENDRAVEN_API_KEY"

Response

200 OK

email is the address trimmed and lower-cased, and scope the scope applied.

{
  "email": "ana@example.com",
  "scope": "marketing",
  "removed": true
}

Errors

StatusTypeWhen
422invalid_requestscope is not one of the listed values.

Add suppressions in bulk

POST /v1/suppressions/batch · requires emails:send

Suppresses up to 10,000 addresses with one reason and one scope. This is the migration path: import your previous provider's unsubscribe list before your first campaign, or everyone who already opted out there is mailed again here.

The defaults differ from a single add. A batch defaults to reason list_hygiene and scope marketing, because an imported opt-out list is about marketing mail. Pass scope: "all" explicitly for a list of hard bounces or complaints.

Addresses are trimmed and lower-cased, then de-duplicated, and written in one bulk operation. Each is written the same way as a single add: re-running an import creates nothing new, and an address already suppressed with the same scope has its reason replaced unless the stored reason is a hard_bounce or complaint. The request returns after every address has been written.

With reason unsubscribe, every address's pending scheduled sends are cancelled and its active automation enrolments end, as for a single add.

Body

FieldTypeRequiredDefaultDescription
emailsarray of stringYesnone1 to 10,000 valid email addresses. One invalid address fails the whole request with 422 and nothing is written.
reason"manual" | "list_hygiene" | "unsubscribe"No"list_hygiene"Applied to every address.
scope"all" | "transactional" | "marketing"No"marketing"Applied to every address.

Example

curl https://api.sendraven.ai/v1/suppressions/batch \
  -X POST \
  -H "Authorization: Bearer $SENDRAVEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "emails": ["ana@example.com", "bo@example.com", "Ana@example.com"],
    "reason": "unsubscribe",
    "scope": "marketing"
  }'

Response

201 Created

{
  "suppressed": 2,
  "duplicates": 1
}
FieldTypeDescription
suppressedintegerThe number of distinct addresses written, including any that were already suppressed with this scope.
duplicatesintegerHow many entries in emails repeated an earlier one after trimming and lower-casing.

Errors

StatusTypeWhen
422invalid_requestemails is missing, empty, longer than 10,000 or contains an invalid address, or reason or scope is not one of the listed values. details lists the problems.

Remove suppressions in bulk

DELETE /v1/suppressions/batch · requires emails:send

Lifts the suppression with the given scope from up to 10,000 addresses. The body goes in the request, even though this is a DELETE.

The scope matches exactly, as in Remove a suppression, and the same warning applies: removal does not check whether a suppression was a hard bounce or a complaint.

Body

FieldTypeRequiredDefaultDescription
emailsarray of stringYesnone1 to 10,000 valid email addresses. Matched after trimming and lower-casing.
scope"all" | "transactional" | "marketing"No"all"The scope of the suppression to remove from each address.

Example

curl https://api.sendraven.ai/v1/suppressions/batch \
  -X DELETE \
  -H "Authorization: Bearer $SENDRAVEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emails": ["ana@example.com", "bo@example.com"], "scope": "marketing" }'

Response

200 OK

{
  "removed": 2
}

removed is the number of suppressions that existed with that scope and were deleted. An address with no suppression in that scope, or repeated in the request, is not counted.

Errors

StatusTypeWhen
422invalid_requestemails is missing, empty, longer than 10,000 or contains an invalid address, or scope is not one of the listed values. details lists the problems.