Suppressions API
Manage the per-team suppression list — addresses blocked from future sends.
Every request needs a bearer token and goes to a path under https://api.anypost.com/v1. See API conventions for the shared request, error, and pagination rules.
List suppressions
GET /v1/suppressions
Returns the authenticated team's suppression list, newest-first,
with cursor pagination. Includes addresses suppressed
automatically from permanent bounces and complaints as well
as manual entries. Rows whose expires_at has
passed are filtered out automatically — they aren't enforced
on send and don't appear here.
Parameters
limitintegerin query[optional]Number of items to return.
afterstringin query[optional]Opaque cursor from a previous response's
next_cursor. Do not parse.email_containsstringin query[optional]Case-insensitive substring match against the suppressed address.
topicstringin query[optional]Restrict to entries scoped to this topic. Pass
*to see only global (bounce/complaint/manual) suppressions, or a specific topic name (e.g.marketing) to see only topic-scoped unsubscribes. Omit to see every topic.reasonstringin query[optional]Restrict to entries with this reason.
One of:
permanent_bounce,complaint,unsubscribed,manual.originstringin query[optional]Restrict to entries added by this origin.
One of:
auto,manual.
Example request
curl https://api.anypost.com/v1/suppressions \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
dataarray of Suppressionhas_morebooleannext_cursorstringMay be null.
{
"data": [
{
"id": "sup_550e8400-e29b-41d4-a716-446655440000",
"email": "[email protected]",
"topic": "*",
"reason": "permanent_bounce",
"origin": "auto",
"classification": "string",
"smtp_code": 0,
"note": "string",
"suppressed_at": "string",
"expires_at": "string",
"created_at": "string"
}
],
"has_more": true,
"next_cursor": "string"
}Responses
| Status | Description |
|---|---|
200 | Paginated list of suppressions. |
401 | Missing or invalid credentials. |
Add a manual suppression
POST /v1/suppressions
Suppresses a single recipient address for the authenticated
team. The email is normalized (trimmed + lowercased) before
storage and uniqueness check, so [email protected] and
[email protected] collide. Manual entries never expire;
use DELETE /suppressions/{email}/{topic} to remove one.
A 422 validation_error is returned if an active suppression
for the same normalized (email, topic) pair already
exists for the team. To remove an entry, call
DELETE /suppressions/{email}/{topic} with the
customer-supplied address (and optional topic) as path
parameters.
Request body
Send as JSON with Content-Type: application/json.
emailstring (email)[required]topicstring[optional]Optional topic to scope the suppression. Omit (or send
*) to block every topic for this address. Send a specific topic (e.g.marketing) to leave other topics — typically transactional traffic — unaffected.notestring[optional]Optional internal annotation (e.g. "customer requested removal"). Preserved if an automatic bounce later re-suppresses this address.
May be null.
Example request
curl https://api.anypost.com/v1/suppressions \
-X POST \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]"
}'Response body
On success (201), the response body is:
idstringStable identifier for log correlation. Lookups and deletes are keyed on
(email, topic), not on this id.emailstring (email)The suppressed recipient address, normalized to lowercase with surrounding whitespace trimmed. Together with
topic, forms the natural key forGET/DELETE /suppressions/{email}/{topic}.topicstringThe topic this suppression is scoped to. The wildcard
*means "every topic" — bounces and complaints always write*so the address is suppressed for all sends. A specific topic (e.g.marketing) only blocks sends tagged with that same topic, leaving transactional traffic (otp,password-reset, …) unaffected. Topics are lowercased on write.reasonstringWhy the address is suppressed.
permanent_bounce— the receiving server reported a permanent delivery failure (e.g.InvalidRecipient,BadDomain). Always topic*.complaint— an ARF feedback report (FBL) classified as abuse, fraud, virus, or opt-out. Always topic*.unsubscribed— the recipient one-click unsubscribed (RFC 8058 POST to/u/{token}). Scoped to the topic from the unsubscribe token.manual— added through the API/UI or via CSV import. Topic-scoped or*.
One of:
permanent_bounce,complaint,unsubscribed,manual.originstringProvenance of the row.
auto— written automatically from a bounce or complaint event.manual— created through this API or the dashboard.
One of:
auto,manual.classificationstringFor
permanent_bounce, the bounce classification (e.g.InvalidRecipient). Forcomplaint, the ARFfeedback-type(abuse,fraud, …). Null for manual entries.May be null.
smtp_codeintegerThe SMTP reply code on the bounce that produced this suppression. Null for complaints and manual entries.
May be null.
notestringFree-form note attached at creation. Preserved across automatic re-suppressions of the same address.
May be null.
suppressed_atstring (date-time)When the suppression was first observed (bounce / complaint timestamp for
auto, creation time for manual).expires_atstring (date-time)When this suppression stops applying. Null means it never expires (complaints and manual entries by default). Permanent bounces expire on a rolling 90-day window.
May be null.
created_atstring (date-time)
{
"id": "sup_550e8400-e29b-41d4-a716-446655440000",
"email": "[email protected]",
"topic": "*",
"reason": "permanent_bounce",
"origin": "auto",
"classification": "string",
"smtp_code": 0,
"note": "string",
"suppressed_at": "string",
"expires_at": "string",
"created_at": "string"
}Responses
| Status | Description |
|---|---|
201 | Suppression created. |
401 | Missing or invalid credentials. |
422 | Request validation failed. |
List every suppression for an email
GET /v1/suppressions/{email}
Returns every suppression record on file for the recipient
address, across all topics. Since a single address can be
suppressed globally (*) and/or scoped to specific topics
(e.g. marketing), this endpoint returns the full set.
The {email} path segment is URL-encoded and matched
case-insensitively after trim + lowercase, so
Alice%40Example.com and alice%40example.com resolve to
the same rows. Returns 404 if no active suppressions exist
for this address on the authenticated team.
To target a single (email, topic) pair, use
GET /suppressions/{email}/{topic} instead.
Parameters
emailstringin path[required]URL-encoded recipient email address.
Example request
curl https://api.anypost.com/v1/suppressions/alice%40example.com \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
dataarray of Suppression
{
"data": [
{
"id": "sup_550e8400-e29b-41d4-a716-446655440000",
"email": "[email protected]",
"topic": "*",
"reason": "permanent_bounce",
"origin": "auto",
"classification": "string",
"smtp_code": 0,
"note": "string",
"suppressed_at": "string",
"expires_at": "string",
"created_at": "string"
}
]
}Responses
| Status | Description |
|---|---|
200 | All suppressions for this address. |
404 | Resource not found. |
Remove every suppression for an email
DELETE /v1/suppressions/{email}
Removes the address from the suppression list across every
topic. After this call the address is immediately eligible
to receive mail again on the next send (regardless of
topic). An automatic bounce or complaint event afterwards
will create a fresh global (*) row; a future one-click
unsubscribe will create a fresh topic-scoped row.
To remove only one topic's row, use
DELETE /suppressions/{email}/{topic} instead.
Parameters
emailstringin path[required]URL-encoded recipient email address.
Example request
curl https://api.anypost.com/v1/suppressions/alice%40example.com \
-X DELETE \
-H "Authorization: Bearer $ANYPOST_API_KEY"Responses
| Status | Description |
|---|---|
204 | Deleted. |
404 | Resource not found. |
Retrieve a suppression by email and topic
GET /v1/suppressions/{email}/{topic}
Returns the single suppression record for the
(email, topic) pair, or 404 if it isn't suppressed for
the authenticated team. Use * as the topic to fetch the
global row written by bounces, complaints, and global
manual entries.
Parameters
emailstringin path[required]URL-encoded recipient email address.
topicstringin path[required]Topic the suppression is scoped to.
*resolves the global row; any other value resolves a topic-scoped unsubscribe / manual entry. URL-encode*as%2Aif your HTTP client does not allow literal asterisks in path segments.
Example request
curl https://api.anypost.com/v1/suppressions/alice%40example.com/marketing \
-H "Authorization: Bearer $ANYPOST_API_KEY"Response body
On success (200), the response body is:
idstringStable identifier for log correlation. Lookups and deletes are keyed on
(email, topic), not on this id.emailstring (email)The suppressed recipient address, normalized to lowercase with surrounding whitespace trimmed. Together with
topic, forms the natural key forGET/DELETE /suppressions/{email}/{topic}.topicstringThe topic this suppression is scoped to. The wildcard
*means "every topic" — bounces and complaints always write*so the address is suppressed for all sends. A specific topic (e.g.marketing) only blocks sends tagged with that same topic, leaving transactional traffic (otp,password-reset, …) unaffected. Topics are lowercased on write.reasonstringWhy the address is suppressed.
permanent_bounce— the receiving server reported a permanent delivery failure (e.g.InvalidRecipient,BadDomain). Always topic*.complaint— an ARF feedback report (FBL) classified as abuse, fraud, virus, or opt-out. Always topic*.unsubscribed— the recipient one-click unsubscribed (RFC 8058 POST to/u/{token}). Scoped to the topic from the unsubscribe token.manual— added through the API/UI or via CSV import. Topic-scoped or*.
One of:
permanent_bounce,complaint,unsubscribed,manual.originstringProvenance of the row.
auto— written automatically from a bounce or complaint event.manual— created through this API or the dashboard.
One of:
auto,manual.classificationstringFor
permanent_bounce, the bounce classification (e.g.InvalidRecipient). Forcomplaint, the ARFfeedback-type(abuse,fraud, …). Null for manual entries.May be null.
smtp_codeintegerThe SMTP reply code on the bounce that produced this suppression. Null for complaints and manual entries.
May be null.
notestringFree-form note attached at creation. Preserved across automatic re-suppressions of the same address.
May be null.
suppressed_atstring (date-time)When the suppression was first observed (bounce / complaint timestamp for
auto, creation time for manual).expires_atstring (date-time)When this suppression stops applying. Null means it never expires (complaints and manual entries by default). Permanent bounces expire on a rolling 90-day window.
May be null.
created_atstring (date-time)
{
"id": "sup_550e8400-e29b-41d4-a716-446655440000",
"email": "[email protected]",
"topic": "*",
"reason": "permanent_bounce",
"origin": "auto",
"classification": "string",
"smtp_code": 0,
"note": "string",
"suppressed_at": "string",
"expires_at": "string",
"created_at": "string"
}Responses
| Status | Description |
|---|---|
200 | The suppression. |
404 | Resource not found. |
Remove a suppression by email and topic
DELETE /v1/suppressions/{email}/{topic}
Removes the single (email, topic) row from the
suppression list. Other topics for the same address are
untouched. After this call sends tagged with this topic
are again eligible for delivery.
Parameters
emailstringin path[required]URL-encoded recipient email address.
topicstringin path[required]
Example request
curl https://api.anypost.com/v1/suppressions/alice%40example.com/marketing \
-X DELETE \
-H "Authorization: Bearer $ANYPOST_API_KEY"Responses
| Status | Description |
|---|---|
204 | Deleted. |
404 | Resource not found. |