Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Sendraven Ai Webhook Endpoints API
version: 1.0.0
description: 'Operations tagged Webhook Endpoints 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: Webhook Endpoints
paths:
/v1/webhook-endpoints:
get:
summary: List webhook endpoints
description: Endpoints newest first, cursor-paged, without their signing secrets.
x-required-scope: webhooks:read
parameters:
- 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: Endpoints, no secret.
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/WebhookEndpoint'
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 webhooks: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:
- Webhook Endpoints
operationId: getV1WebhookEndpoints
x-operation-id-source: derived
post:
summary: Subscribe a URL to events
description: 'Creates an enabled endpoint. The signing secret is in this response and nowhere else, and cannot be rotated: store it first; to replace a lost one, create a new endpoint and delete the old. Verify the X-CN-Signature header on every delivery. The URL must be a public http or https address on port 80, 443 or 1024 to 65535 (or no port): another port, a URL with credentials, an IP address (or a name resolving to one, any record) in a private, loopback, link-local or other non-public range, a local name (localhost, .internal, .local, .localdomain, .home.arpa) or a single label with no dot is refused with 422. A name that does not resolve yet is accepted, and every delivery checks again. Prefer https; payloads carry recipient addresses. This response is never stored for idempotency, so a retry with the same Idempotency-Key after it answered creates a second endpoint with its own secret; after a timeout, list endpoints before retrying.'
x-required-scope: webhooks:write
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- url
- events
properties:
url:
type: string
format: uri
description: An absolute, public http or https URL.
events:
type: array
minItems: 1
items:
type: string
enum:
- inbound
- send
- delivery
- bounce
- complaint
- reject
- open
- click
- rendering_failure
- delivery_delay
- unsubscribe
description: inbound (a message arrived, usually a reply), send, delivery, bounce, complaint, reject, open (first open only), click (every click), rendering_failure, delivery_delay, unsubscribe (a person opted out of all marketing or of one topic, through a link, one-click, the preference centre or POST /v1/topics/preferences; sent once per change, first attempt within about 30 seconds). open and click are recorded only for identities whose link. tracking hostname is active.
responses:
'201':
description: Created, with the signing secret (the only time it is returned).
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookEndpointWithSecret'
'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 webhooks:write 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: url missing or not a URL, on a port other than 80, 443 or 1024-65535 ("url: port must be 80, 443 or 1024-65535"), or not a public http or https address; or events missing, empty or containing an unknown type. 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:
- Webhook Endpoints
operationId: postV1WebhookEndpoints
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/webhook-endpoints/{id}:
patch:
summary: Update a webhook endpoint
description: 'Changes the URL, events or enabled state; fields left out are unchanged, unknown fields ignored, and events replaces the whole list. The secret stays the same. enabled: false stops new deliveries and records retries that fall due as failed attempts ("endpoint removed or disabled"); deliveries with attempts left are retried again once re-enabled. A new url must be a public http or https address on an allowed port, as on creation. The endpoint is looked up before the body is validated.'
x-required-scope: webhooks:write
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: The webhook endpoint's id from GET /v1/webhook-endpoints (a UUID), not its URL.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
url:
type: string
format: uri
description: An absolute, public http or https URL.
events:
type: array
minItems: 1
items:
type: string
enum:
- inbound
- send
- delivery
- bounce
- complaint
- reject
- open
- click
- rendering_failure
- delivery_delay
- unsubscribe
enabled:
type: boolean
description: false pauses deliveries, true resumes them.
responses:
'200':
description: The endpoint as stored after the update, without its secret.
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookEndpoint'
'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 webhooks:write scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no webhook endpoint with this id in the workspace ("No such webhook endpoint").'
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: url not a URL, on a port other than 80, 443 or 1024-65535, or not a public http or https address; events empty or containing an unknown type; or enabled not a boolean. 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:
- Webhook Endpoints
operationId: patchV1WebhookEndpointsById
x-operation-id-source: derived
delete:
summary: Delete a webhook endpoint
description: 'Removes the endpoint: no further deliveries, retries still owed are recorded as failed, and its delivery attempts can no longer be listed. To pause without losing the endpoint and its secret, PATCH enabled: false.'
x-required-scope: webhooks:write
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: The webhook endpoint's id from GET /v1/webhook-endpoints (a UUID), not its URL.
responses:
'200':
description: Deleted.
content:
application/json:
schema:
type: object
required:
- id
- deleted
properties:
id:
type: string
format: uuid
deleted:
type: boolean
enum:
- true
'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 webhooks:write scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no webhook endpoint with this id in the workspace ("No such webhook endpoint").'
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:
- Webhook Endpoints
operationId: deleteV1WebhookEndpointsById
x-operation-id-source: derived
servers:
- url: https://api.sendraven.ai
/v1/webhook-endpoints/{id}/events:
get:
summary: List delivery attempts for an endpoint
description: 'The answer to "why didn''t my webhook fire?": the most recent deliveries to this endpoint, newest first, one row per event with its latest attempt''s outcome. Tells "SendRaven never sent it" apart from "the endpoint answered 500". The first attempt is made when the event happens; failures are retried up to six attempts in all (about +1m, +5m, +30m, +2h, +12h from the event). Not paged: cursor is ignored, next_cursor is always null, and has_more is true when the page came back full, meaning older attempts may exist that this cannot reach.'
x-required-scope: webhooks:read
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: The webhook endpoint's id from GET /v1/webhook-endpoints (a UUID), not its URL.
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 200
default: 50
description: How many recent deliveries to return. Capped at 200; a fraction is truncated; zero, a negative or a non-number falls back to 50. None of these is an error.
responses:
'200':
description: Recent deliveries, in the list envelope.
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/WebhookDelivery'
has_more:
type: boolean
description: 'Not paged: true only when the list hit its cap, meaning there is more than this endpoint can return.'
next_cursor:
type:
- string
- 'null'
description: Always null; this list is not paged.
'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 webhooks:read scope. The message names it.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 'not_found: no webhook endpoint with this id in the workspace ("No such webhook endpoint").'
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:
- Webhook Endpoints
operationId: getV1WebhookEndpointsByIdEvents
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.'
WebhookDelivery:
type: object
description: One event delivered (or being delivered) to an endpoint, with the outcome of its latest attempt.
required:
- id
- event
- status
- attempts
- last_status_code
- last_error
- created_at
- delivered_at
properties:
id:
type: string
format: uuid
event:
type: string
enum:
- inbound
- send
- delivery
- bounce
- complaint
- reject
- open
- click
- rendering_failure
- delivery_delay
- unsubscribe
status:
type: string
enum:
- pending
- success
- failed
description: pending before the first attempt finishes, success once an attempt got a 2xx, failed after an attempt that did not. A failed delivery with fewer than six attempts is still being retried.
attempts:
type: integer
description: Attempts made so far, at most six.
last_status_code:
type:
- integer
- 'null'
description: The HTTP status the endpoint returned on the most recent attempt that got a response.
last_error:
type:
- string
- 'null'
description: The most recent error that prevented a usable response (timeout, refused connection, a redirect, a destination that resolves to a non-public address, the endpoint removed or disabled), up to 500 characters. A later success does not clear it.
created_at:
type: string
format: date-time
description: When the event was queued for this endpoint.
delivered_at:
type:
- string
- 'null'
format: date-time
description: When an attempt succeeded.
WebhookEndpointWithSecret:
type: object
description: 'The endpoint as created, with its signing secret: the only response that ever carries it.'
required:
- id
- url
- events
- enabled
- created_at
- secret
properties:
id:
type: string
format: uuid
url:
type: string
events:
type: array
items:
type: string
enum:
- inbound
- send
- delivery
- bounce
- complaint
- reject
- open
- click
- rendering_failure
- delivery_delay
- unsubscribe
enabled:
type: boolean
created_at:
type: string
format: date-time
secret:
type: string
description: 'Starts whsec_. Signs every delivery in the X-CN-Signature header (t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<body>">). Store it now: it cannot be read back or rotated.'
WebhookEndpoint:
type: object
description: A webhook endpoint. The signing secret is left out of every response except creation.
required:
- id
- url
- events
- enabled
- created_at
properties:
id:
type: string
format: uuid
url:
type: string
description: Where deliveries are POSTed.
events:
type: array
items:
type: string
enum:
- inbound
- send
- delivery
- bounce
- complaint
- reject
- open
- click
- rendering_failure
- delivery_delay
- unsubscribe
enabled:
type: boolean
description: Whether deliveries are made. True on creation.
created_at:
type: string
format: date-time
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