Skip to content

Deliveries

Every send attempt writes a delivery record: sentdelivered / bounced / complained (status precedence means a late delivered never overwrites bounced, and a complaint outranks a bounce), failed, a typed skipped_*, or a dry-run would_*. A webhook’s 2xx is its delivery confirmation, so it is terminal at delivered. The public endpoints are what SNS (carrying SES’s event stream) and mail clients (RFC 8058 one-click unsubscribe) call: they verify signatures/tokens instead of sessions and answer per the caller’s convention, not the envelope. The address-verification pages are on the Emails page.

List deliveries, newest first

Auth: Clerk session token, or an org deploy key.

Query parameters

{
"cursor": "string",
"limit": 50,
"direction": "desc",
"status": "sent",
"journey": "string",
"channel": "email",
"appId": "string",
"profileId": "string",
"since": "2026-01-15T09:30:00.000Z"
}
Field Type Required Constraints
cursor string no
limit integer no default 50; 1 ≤ x ≤ 100
direction “asc” | “desc” no default "desc"
status “sent” | “delivered” | “bounced” | “complained” | “failed” | “skipped_disabled” | “skipped_paused” | “skipped_suppressed” | “skipped_quota” | “skipped_frequency_cap” | “skipped_consent” | “skipped_domain” | “skipped_ssrf” | “would_send” | “would_skip_disabled” | “would_skip_paused” | “would_skip_suppressed” | “would_skip_quota” | “would_skip_frequency_cap” | “would_skip_consent” | “would_skip_domain” | “would_skip_ssrf” no
journey string no length 1–200
channel “email” | “webhook” no
appId string no length 1–200
profileId string no length 1–200
since string (date-time) no

Response 200

{
"data": [
{
"id": "string",
"orgId": "string",
"environment": "development",
"profileId": "string",
"journey": "string",
"step": "string",
"channel": "email",
"status": "sent",
"dryRun": true,
"recipient": "string",
"providerId": "string",
"error": "string",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z",
"sentAt": "2026-01-15T09:30:00.000Z",
"settledAt": "2026-01-15T09:30:00.000Z"
}
],
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object[] yes
data[] object yes
data[].id string yes
data[].orgId string yes
data[].environment “development” | “production” yes
data[].profileId string yes
data[].journey string yes
data[].step string yes
data[].channel “email” | “webhook” yes
data[].status “sent” | “delivered” | “bounced” | “complained” | “failed” | “skipped_disabled” | “skipped_paused” | “skipped_suppressed” | “skipped_quota” | “skipped_frequency_cap” | “skipped_consent” | “skipped_domain” | “skipped_ssrf” | “would_send” | “would_skip_disabled” | “would_skip_paused” | “would_skip_suppressed” | “would_skip_quota” | “would_skip_frequency_cap” | “would_skip_consent” | “would_skip_domain” | “would_skip_ssrf” yes
data[].dryRun boolean yes
data[].recipient string | null yes
data[].providerId string | null yes
data[].error string | null yes
data[].createdAt string (date-time) yes
data[].updatedAt string (date-time) yes
data[].sentAt string (date-time) | null yes
data[].settledAt string (date-time) | null yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Fetch one delivery with its payload

Auth: Clerk session token, or an org deploy key.

Response 200

{
"data": {
"id": "string",
"orgId": "string",
"environment": "development",
"profileId": "string",
"journey": "string",
"step": "string",
"channel": "email",
"status": "sent",
"dryRun": true,
"recipient": "string",
"providerId": "string",
"error": "string",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z",
"sentAt": "2026-01-15T09:30:00.000Z",
"settledAt": "2026-01-15T09:30:00.000Z",
"payload": {
"rendered": {
"subject": "string",
"html": "string",
"text": "string"
}
}
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.id string yes
data.orgId string yes
data.environment “development” | “production” yes
data.profileId string yes
data.journey string yes
data.step string yes
data.channel “email” | “webhook” yes
data.status “sent” | “delivered” | “bounced” | “complained” | “failed” | “skipped_disabled” | “skipped_paused” | “skipped_suppressed” | “skipped_quota” | “skipped_frequency_cap” | “skipped_consent” | “skipped_domain” | “skipped_ssrf” | “would_send” | “would_skip_disabled” | “would_skip_paused” | “would_skip_suppressed” | “would_skip_quota” | “would_skip_frequency_cap” | “would_skip_consent” | “would_skip_domain” | “would_skip_ssrf” yes
data.dryRun boolean yes
data.recipient string | null yes
data.providerId string | null yes
data.error string | null yes
data.createdAt string (date-time) yes
data.updatedAt string (date-time) yes
data.sentAt string (date-time) | null yes
data.settledAt string (date-time) | null yes
data.payload record<string, any> yes
data.payload.rendered object no
data.payload.rendered.subject string yes
data.payload.rendered.html string yes
data.payload.rendered.text string yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

SES delivery feedback via SNS (public)

Auth: None: verifies the caller’s own signature/token.

Errors follow the shared envelope and code table.

One-click unsubscribe (public)

Auth: None: verifies the caller’s own signature/token.

Query parameters

{
"token": "string"
}
Field Type Required Constraints
token string no

Errors follow the shared envelope and code table.

Unsubscribe confirmation page (public)

Auth: None: verifies the caller’s own signature/token.

Query parameters

{
"token": "string"
}
Field Type Required Constraints
token string no

Errors follow the shared envelope and code table.