Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Sendraven Ai Suppressions API
version: 1.0.0
description: 'Operations tagged Suppressions across 2 of this provider''s published API definitions: sendraven-ai-api-openapi.json, sendraven-ai-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.sendraven.ai
security:
- bearerAuth: []
tags:
- name: Suppressions
paths:
/v1/suppressions:
get:
summary: List addresses we refuse to mail
description: 'Check here first when someone reports not receiving email. Pass ?email= to answer it for one address: data then holds every suppression that address has, one per scope, and an empty data means it is not suppressed at all (topic opt-outs are separate; see GET /v1/topics/preferences). Newest first, cursor-paged.'
x-required-scope: emails:read
parameters:
- name: email
in: query
schema:
type: string
description: Only this address, matched after trimming and lower-casing; returns every scope it is suppressed for.
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 50
description: Page size. A larger value is capped at 100, a fraction is rounded down, and zero, a negative or a non-number falls back to 50. None of these is an error.
- name: cursor
in: query
schema:
type: string
description: The next_cursor from the previous page, passed back unchanged. An unreadable cursor returns the first page.
responses:
'200':
description: Suppressions, newest first.
content:
application/json:
schema:
type: object
required:
- object
- data
- has_more
- next_cursor
properties:
object:
type: string
enum:
- list
data:
type: array
items:
$ref: '#/components/schemas/Suppression'
has_more:
type: boolean
description: True when another page exists; pass next_cursor back as cursor.
next_cursor:
type:
- string
- 'null'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the emails:read scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Suppressions
operationId: getV1Suppressions
x-operation-id-source: derived
post:
summary: Suppress an address
description: 'Takes effect on the next send, including scheduled mail and running campaigns and automations, which re-check at each address''s turn. Idempotent on (address, scope): an existing row keeps its id, created_at and detail, and its reason is replaced unless the stored one is hard_bounce or complaint; the response reason is the one that stands. A narrower scope writes a separate row and the broader one still blocks. With reason unsubscribe this is an unsubscribe, which is two writes: the suppression, and ending the person''s queued mail (pending scheduled sends cancelled, active automation enrolments ended), whatever the scope. It does not change the contact record or topic preferences. For someone who opted out of newsletters, send reason unsubscribe with scope marketing so transactional mail still arrives.'
x-required-scope: emails:send
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
format: email
description: Stored trimmed and lower-cased.
reason:
type: string
enum:
- manual
- list_hygiene
- unsubscribe
default: manual
description: hard_bounce and complaint cannot be set here. unsubscribe also ends queued mail.
scope:
type: string
enum:
- all
- transactional
- marketing
default: all
description: 'Which mail the suppression blocks, matched against the message''s risk class: all blocks everything, transactional only transactional mail, marketing only marketing mail (campaigns, automations and sends marked marketing). Use marketing for someone who asked to stop newsletters, so their password resets still arrive.'
responses:
'201':
description: The suppression as it stands after the write, the same object the list returns. 201 whether or not the address was already suppressed.
content:
application/json:
schema:
$ref: '#/components/schemas/Suppression'
'400':
description: 'invalid_json: the request body is not valid JSON.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the emails:send scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'invalid_request: email missing or invalid, or reason or scope not a listed value. details lists the problems. Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
parameters:
- name: Idempotency-Key
in: header
schema:
type: string
description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
tags:
- Suppressions
operationId: postV1Suppressions
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/suppressions/batch:
post:
summary: Suppress many addresses
description: 'The migration path: import the previous provider''s unsubscribe list before the first campaign, or everyone who already opted out there is mailed again. Up to 10,000 addresses with one reason and one scope. The defaults differ from a single add: reason list_hygiene, scope marketing. Pass scope all explicitly for hard bounces or complaints. Addresses are trimmed, lower-cased, de-duplicated and written in one bulk operation with the same rules as a single add, so re-running an import creates nothing new. With reason unsubscribe every address''s pending scheduled sends are cancelled and its active enrolments end. One invalid address fails the whole request and nothing is written.'
x-required-scope: emails:send
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- emails
properties:
emails:
type: array
minItems: 1
maxItems: 10000
items:
type: string
format: email
reason:
type: string
enum:
- manual
- list_hygiene
- unsubscribe
default: list_hygiene
scope:
type: string
enum:
- all
- transactional
- marketing
default: marketing
description: 'Which mail the suppression blocks, matched against the message''s risk class: all blocks everything, transactional only transactional mail, marketing only marketing mail (campaigns, automations and sends marked marketing). Use marketing for someone who asked to stop newsletters, so their password resets still arrive.'
responses:
'201':
description: Written.
content:
application/json:
schema:
$ref: '#/components/schemas/SuppressionBatchResult'
'400':
description: 'invalid_json: the request body is not valid JSON.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the emails:send scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: 'idempotency_in_progress: a request with the same Idempotency-Key was still running on this path after waiting up to 8 seconds for it (a retry that finds it finished receives its response instead). Retry after a short wait.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'invalid_request: emails missing, empty, over 10,000 or containing an invalid address, or reason or scope not a listed value. details lists the problems. Also idempotency_key_reused: this Idempotency-Key was already used on this path with a different request body (checked right after the scope, so a credential without the scope gets 403 instead, and answered at once even while the first request is still running). Do not retry; send the new request under a new key.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
parameters:
- name: Idempotency-Key
in: header
schema:
type: string
description: 'Replaying the same key on the same path in this workspace within 24 hours returns the stored response, with an Idempotent-Replay: true header, instead of acting again. Only successful responses are stored, so a failed request can be fixed and retried under the same key. The body is compared (key order ignored): the same key with a different body is 422 idempotency_key_reused, so use a new key for every new request. Use an unguessable value such as a UUID.'
tags:
- Suppressions
operationId: postV1SuppressionsBatch
x-operation-id-source: derived
delete:
summary: Remove suppressions from many addresses
description: 'Lifts the suppression with exactly this scope from up to 10,000 addresses; the body goes in the DELETE request. Removing scope all leaves a marketing suppression in place. Removal does not check the reason: lifting a hard_bounce or complaint re-enables mail to a dead mailbox or to someone who reported spam, which raises the rates AWS pauses accounts on. Never lift suppressions to work around failed sends.'
x-required-scope: emails:send
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- emails
properties:
emails:
type: array
minItems: 1
maxItems: 10000
items:
type: string
format: email
description: Matched after trimming and lower-casing.
scope:
type: string
enum:
- all
- transactional
- marketing
default: all
description: The scope of the suppression to remove from each address. Matches exactly.
responses:
'200':
description: Removed.
content:
application/json:
schema:
$ref: '#/components/schemas/SuppressionBatchRemoveResult'
'400':
description: 'invalid_json: the request body is not valid JSON.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the emails:send scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'413':
description: 'payload_too_large: the body is larger than this endpoint accepts (5 MB unless stated).'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'invalid_request: emails missing, empty, over 10,000 or containing an invalid address, or scope not a listed value. details lists the problems.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Suppressions
operationId: deleteV1SuppressionsBatch
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/suppressions/{email}:
delete:
summary: Remove a suppression
description: 'Lifts one address''s suppression in exactly one scope: removing all leaves a marketing suppression in place, so list the address with ?email= first to see every scope it holds. Removal does not check the reason. Lifting a hard_bounce or complaint lets us mail an address that does not exist or that reported spam, which raises the rates AWS enforces on. Never clear a suppression to work around a failed send. removed: false means nothing existed in that scope.'
x-required-scope: emails:send
parameters:
- name: email
in: path
required: true
schema:
type: string
description: The address, URL-encoded. Not validated; matched after trimming and lower-casing.
- name: scope
in: query
schema:
type: string
enum:
- all
- transactional
- marketing
default: all
description: The scope of the suppression to remove. Matches exactly.
responses:
'200':
description: Whether a suppression was removed.
content:
application/json:
schema:
$ref: '#/components/schemas/SuppressionRemoveResult'
'401':
description: 'unauthorized: no Bearer token, or the key or token is invalid, revoked or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'forbidden: the key lacks the emails:send scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'422':
description: 'invalid_request: scope is not all, transactional or marketing.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'rate_limited: more requests than the per-key rate (600 a minute by default). Wait the seconds in the Retry-After header and retry.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: 'service_unavailable: the API is under heavy load and could not get a database connection in time. Usually nothing was done; a send that was already under way may have been, so check GET /v1/emails before retrying one. Wait the seconds in the Retry-After header.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Suppressions
operationId: deleteV1SuppressionsByEmail
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
components:
schemas:
Error:
type: object
required:
- error
properties:
error:
type: object
required:
- type
- message
properties:
type:
type: string
description: 'Stable and safe to branch on, and the same status on every route: invalid_request (422), invalid_json (400), payload_too_large (413), unauthorized (401), forbidden (403), not_found (404), conflict (409, an identifier already taken), invalid_state (409, the resource''s current state does not allow this), plan_limit_reached (402), payment_method_required (402), billing_past_due (402), budget_exceeded (402), no_verified_identity (422), missing_variables (422), unknown_topic (422), idempotency_in_progress (409), idempotency_key_reused (422), approval_in_progress (409), rate_limited (429), daily_limit (429), recipient_not_allowed (403), invalid_schedule (422), warmup_limit (422), no_postal_address (422), workspace_suspended (422), gone (410), ses_error (502), internal_error (500), service_unavailable (503).'
message:
type: string
description: For people; may change.
details:
type: array
items:
type: object
additionalProperties: true
description: 'On many 422 invalid_request answers: one entry per field that failed validation.'
missing:
type: array
items:
type: string
description: 'Only on missing_variables, and always there: the names of the template variables that were not supplied.'
SuppressionBatchRemoveResult:
type: object
required:
- removed
properties:
removed:
type: integer
description: 'Suppressions that existed with that scope and were deleted. Not the number of addresses sent: an address with nothing in that scope, or repeated, is not counted.'
SuppressionBatchResult:
type: object
required:
- suppressed
- duplicates
properties:
suppressed:
type: integer
description: Distinct addresses written, including any already suppressed with this scope.
duplicates:
type: integer
description: Entries in emails that repeated an earlier one after trimming and lower-casing.
Suppression:
type: object
description: One suppressed address in one scope. The list and POST /v1/suppressions return this same object, with every field present.
required:
- id
- email
- reason
- scope
- detail
- created_at
properties:
id:
type: string
format: uuid
email:
type: string
description: Trimmed and lower-cased.
reason:
type: string
enum:
- hard_bounce
- complaint
- unsubscribe
- manual
- list_hygiene
description: hard_bounce and complaint are set by SendRaven (or a contact import) with scope all and are never replaced by a weaker reason, so after a POST this can differ from the reason sent. unsubscribe comes from unsubscribe links and the preference centre, with scope marketing. manual and list_hygiene are set by callers.
scope:
type: string
enum:
- all
- transactional
- marketing
description: 'Which mail the suppression blocks, matched against the message''s risk class: all blocks everything, transactional only transactional mail, marketing only marketing mail (campaigns, automations and sends marked marketing). Use marketing for someone who asked to stop newsletters, so their password resets still arrive.'
detail:
type:
- string
- 'null'
maxLength: 500
description: The SMTP diagnostic for a bounce, the feedback type for a complaint, how someone unsubscribed, or the import it came from. null when there is none. Never set through this API.
created_at:
type: string
format: date-time
description: When the address was first suppressed with this scope.
SuppressionRemoveResult:
type: object
required:
- email
- scope
- removed
properties:
email:
type: string
description: The address, trimmed and lower-cased.
scope:
type: string
enum:
- all
- transactional
- marketing
removed:
type: boolean
description: True when a suppression with exactly this scope existed and was deleted. False usually means the address is suppressed under another scope, or not at all; check GET /v1/suppressions?email=.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: An API key of the form sk_live_…, created at /developers, or an OAuth access token (srv_oat_…). An OAuth token carries its grant's scopes but none of an API key's guardrails, and cannot decide approvals.
x-refined-from:
- sendraven-ai-api-openapi.json
- sendraven-ai-openapi.json