Suppression
Suppressions API
5 endpoints under https://api.mailneo.co/api/v2. Every request carries your key in the X-API-Key header. The scopes used here: suppressions:delete, suppressions:read, suppressions:write. Each endpoint below states the one it requires. Start with the guide →
listSuppressionsList suppressed addresses
The addresses this team must not mail. Cursor-paginated. Pass updated_since with the synced_through value from your previous run to fetch only what changed.
This list is complete for your team. Mirror it into your own sender if you send outside Mailneo.
/suppressionssuppressions:readExample request
curl "https://api.mailneo.co/api/v2/suppressions?limit=25&order=desc&sort=updated_at" \ -H "X-API-Key: $MAILNEO_API_KEY"
Authorization
- Required scope
suppressions:read. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Query parameters7
| Name | Type | Required | Notes |
|---|---|---|---|
| limit | integer | No | default 25 · 1–100 |
| cursor | string | No | max 256 chars |
| order | "asc" | "desc" | No | default "desc" |
| updated_since | string · date-time | No | ISO 8601 |
| sort | "updated_at" | "created_at" | No | default "updated_at" |
| string | No | max 320 chars | |
| reason | string | No | max 200 chars |
Response · 200
Success
data[]Each element of the array.
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "suppression" | Yes | |
| id | string | Yes | |
| string | Yes | ||
| reason | string | Yes | |
| created_at | string | Yes | |
| updated_at | string | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| has_more | boolean | Yes | |
| next_cursor | string · nullable | Yes | |
| synced_through | string | No |
addSuppressionsAdd addresses to the suppression list
Suppresses up to 100 addresses per call. Every send path consults this list, so an address added here stops receiving campaign and newsletter mail from this team immediately.
Suppression is an overlay, not a deletion: contacts and subscribers with these addresses are NOT deleted or modified, their list memberships survive, and removing the suppression later restores mailability (except where a per-list opt-out also applies). To erase a person, use the contact delete or the account data-erasure flow — this endpoint only blocks sending.
Partial novelty is the normal outcome and the response says which addresses landed where: added, or already_suppressed (left completely untouched — the existing record keeps its original reason, so a bounce or complaint record is never overwritten by a manual re-post, and its updated_at does not move). Re-posting the same batch is therefore always safe, which is what a retried compliance sync needs. Addresses are normalised (trimmed and lower-cased) before anything else happens.
reason accepts only MANUAL. The other values you will see on reads (bounce:hard, bounce:complaint, unsubscribe variants) are written by the delivery pipeline about its own observations and cannot be set through the API.
suppression.added webhook events are not emitted for additions made through this endpoint.
/suppressionssuppressions:writeExample request
curl -X POST "https://api.mailneo.co/api/v2/suppressions" \
-H "X-API-Key: $MAILNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"emails": [
"<string>"
]
}'Authorization
- Required scope
suppressions:write. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...- Idempotency
Idempotency-Keyis optional.
Query parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| dry_run | boolean | No | Report what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false. |
Header parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| Idempotency-Key | string | No | A caller-chosen unique string, at most 255 characters. Retrying with the same key replays the first response instead of repeating the work; the replay carries Idempotent-Replayed: true. Reusing a key with a different body is a 409 idempotency_key_reused. Keys are remembered for 24 hours. · max 255 chars |
Request body
Body
| Field | Type | Always present | Notes |
|---|---|---|---|
| emails | string[] | Yes | |
| reason | "MANUAL" | No | default "MANUAL" |
Response · 200
Success
dataMay be null.
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "suppression_batch" | Yes | |
| added | string[] | Yes | |
| already_suppressed | string[] | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| dry_run | boolean | Yes | |
| impact | object | No | |
| impact.object | "impact" | Yes | |
| impact.would_create | integer | Yes | |
| impact.would_update | integer | Yes | |
| impact.would_delete | integer | Yes | |
| impact.affected_count | integer | Yes | |
| impact.affected_ids | string[] | Yes | |
| impact.quota | object · nullable | Yes | |
| impact.quota.kind | string | Yes | |
| impact.quota.would_consume | integer | Yes | |
| impact.quota.limit | integer · nullable | Yes | |
| impact.quota.current | integer | Yes |
getSuppressionCheck whether an address is suppressed
Returns the suppression record for an address, or 404 if it is not suppressed. This is the check to run before mailing someone from your own system. The address must be URL-encoded.
/suppressions/{email}suppressions:readExample request
curl "https://api.mailneo.co/api/v2/suppressions/{email}" \
-H "X-API-Key: $MAILNEO_API_KEY"Authorization
- Required scope
suppressions:read. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Path parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| string | Yes | max 320 chars |
Response · 200
Success
data
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "suppression" | Yes | |
| id | string | Yes | |
| string | Yes | ||
| reason | string | Yes | |
| created_at | string | Yes | |
| updated_at | string | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes |
listUnsubscribesList unsubscribe events
The unsubscribe events behind the suppression list — who opted out, from where, and from which campaign. Cursor-paginated.
updated_since is not supported here: the underlying record has no modification timestamp. Unsubscribes are append-only, so page by unsubscribed_at and keep the newest value you have seen as your high-water mark.
/unsubscribessuppressions:readExample request
curl "https://api.mailneo.co/api/v2/unsubscribes?limit=25&order=desc&sort=unsubscribed_at" \ -H "X-API-Key: $MAILNEO_API_KEY"
Authorization
- Required scope
suppressions:read. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Query parameters7
| Name | Type | Required | Notes |
|---|---|---|---|
| limit | integer | No | default 25 · 1–100 |
| cursor | string | No | max 256 chars |
| order | "asc" | "desc" | No | default "desc" |
| sort | "unsubscribed_at" | "created_at" | No | default "unsubscribed_at" |
| string | No | max 320 chars | |
| source | string | No | max 100 chars |
| campaign_id | string | No | max 64 chars |
Response · 200
Success
data[]Each element of the array.
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "unsubscribe" | Yes | |
| id | string | Yes | |
| string | Yes | ||
| reason | string · nullable | Yes | |
| source | string | Yes | |
| campaign_id | string · nullable | Yes | |
| unsubscribed_at | string | Yes | |
| created_at | string | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| has_more | boolean | Yes | |
| next_cursor | string · nullable | Yes |
deleteSuppressionRemove an address from the suppression list (un-suppress)
Removes one suppression record, RE-ENABLING mail to an address that was deliberately blocked: every campaign and newsletter send path in this team will treat the address as mailable again the moment this returns. There is no undo beyond re-adding the suppression — call with ?dry_run=true first.
Check the record's reason before deleting. MANUAL rows were typed in by a person; bounce:hard, bounce:soft and bounce:complaint rows were recorded by the delivery pipeline, and UNSUBSCRIBED/unsubscribe rows record an opt-out. Removal is allowed whatever the reason — the same rule as the in-app suppression screen — but removing a bounce- or complaint-sourced record does not fix what caused it, and the pipeline will re-create the suppression automatically if the condition recurs (another hard bounce, another complaint). Un-suppressing an opt-out and then mailing the address is a compliance decision that is yours, not the platform's.
Only the suppression record is removed. The unsubscribe EVENT history (GET /unsubscribes) is untouched, and a per-list opt-out (an UNSUBSCRIBED list membership) still stands and still blocks that list's sends — this endpoint lifts the team-wide block, nothing else.
Find the id via GET /suppressions or GET /suppressions/{email}. The response deliberately does not echo the address.
/suppressions/{suppressionId}suppressions:deleteExample request
curl -X DELETE "https://api.mailneo.co/api/v2/suppressions/{suppressionId}" \
-H "X-API-Key: $MAILNEO_API_KEY"Authorization
- Required scope
suppressions:delete. A key without it is refused before the endpoint runs.- Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Path parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| suppressionId | string | Yes | max 64 chars |
Query parameters1
| Name | Type | Required | Notes |
|---|---|---|---|
| dry_run | boolean | No | Report what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false. |
Response · 200
Success
dataMay be null.
| Field | Type | Always present | Notes |
|---|---|---|---|
| object | "suppression" | Yes | |
| id | string | Yes | |
| deleted | true | Yes |
meta
| Field | Type | Always present | Notes |
|---|---|---|---|
| request_id | string | Yes | |
| dry_run | boolean | Yes | |
| impact | object | No | |
| impact.object | "impact" | Yes | |
| impact.would_create | integer | Yes | |
| impact.would_update | integer | Yes | |
| impact.would_delete | integer | Yes | |
| impact.affected_count | integer | Yes | |
| impact.affected_ids | string[] | Yes | |
| impact.quota | object · nullable | Yes | |
| impact.quota.kind | string | Yes | |
| impact.quota.would_consume | integer | Yes | |
| impact.quota.limit | integer · nullable | Yes | |
| impact.quota.current | integer | Yes |