Skip to the documentation
API

Webhook events and stats

The events an endpoint can subscribe to, and how the deliveries went.

GET/webhooks/events

Runs any of 2 calls on your workspace.

Events

GET /webhooks/events lists every event an endpoint can name in eventTypes, each with a sentence saying when it fires, and the limits an endpoint is held to: maxEndpoints for the workspace, which its plan decides, and maxAddresses and maxDomains for one allowlist. It needs webhooks:read.

GET /webhooks/events
{  "object": "webhook_catalogue",  "events": [    { "id": "email.received", "label": "A message arrives in this mailbox" },    { "id": "email.sent", "label": "A message goes out, however it was sent" },    { "id": "contact.unsubscribed", "label": "Someone unsubscribes from one of your audiences" },    { "id": "sending.paused", "label": "A sending lane of the workspace is paused" }  ],  "maxEndpoints": 10,  "maxAddresses": 50,  "maxDomains": 25}

An endpoint that names no events receives every email event except email.replied, so email.replied and the other families reach only an endpoint that asks for them by name. The list leaves out automation.webhook, which no endpoint subscribes to: a webhook step of an automation sends it to the endpoint the step names.

Stats

GET /webhooks/stats reads how the deliveries went inside a window, the Analytics tab of the Webhooks page: attempts, delivered and failed, the median time a receiver took to answer, a series of buckets, the events sent and the response codes received. It needs webhooks:read. endpointIds narrows it to some endpoints, since and until set the window, 30 days by default, and grain and offsetMinutes shape the series. Each try of an event counts as one attempt.

GET /webhooks/stats?grain=day
{  "object": "webhook_stats",  "since": "2026-09-02T00:00:00.000Z",  "until": "2026-10-02T00:00:00.000Z",  "grain": "day",  "endpointIds": [],  "totals": { "attempts": 1280, "delivered": 1266, "failed": 14, "medianDurationMs": 212 },  "buckets": [{ "bucket": "2026-09-28", "delivered": 44, "failed": 1 }],  "events": [{ "id": "email.delivered", "count": 702 }],  "codes": [{ "id": "200", "count": 1266 }, { "id": "503", "count": 14 }]}

Payloads

Every delivery is a POST whose JSON body is { id, type, createdAt, data }. id stays the same on every retry and every replay of one event, so keep the ids you have handled and skip one you have seen. data has the shape of its event, listed below and in the webhooks section of /openapi.json, and the TypeScript and Python SDKs type every one of them. Fields can be added to data, never renamed or taken away, so ignore the ones you do not know.

email.received
{  "id": "evt_4f1c9a2e7b3d4c5e8f9a0b1c",  "type": "email.received",  "createdAt": "2026-10-14T09:12:40.118Z",  "data": {    "emailId": "msg_7c2e9a41b3d84f6e9a0c1d2e",    "threadId": "thr_2b8e4c1a9d7f4e3b8a6c5d0e",    "messageId": "<CAHk7pQ2x9LmZ4@mail.example.com>",    "from": "ada@example.com",    "fromName": "Ada Lovelace",    "date": "2026-10-14T09:12:31.000Z",    "subject": "The invoice for October",    "to": "billing@acme.com",    "attachments": [      { "id": "msg_7c2e9a41b3d84f6e9a0c1d2e-1", "filename": "invoice.pdf", "mimeType": "application/pdf", "size": 48213 }    ],    "tags": {},    "spam": false,    "encryption": null  }}
EventFields in `data`SDK type
email.receivedemailId, threadId, messageId, from, fromName, date, subject, to, attachments, tags, spam, muted, encryption, rulesEmailReceivedEventData
email.repliedemailId, threadId, messageId, from, fromName, date, subject, to, tags, repliesToEmailRepliedEventData
email.sentemailId, from, tags, transport, messageId, threadId, subject, trackedMessageId, source, simulated, test, noteEmailSentEventData
email.failedemailId, from, tags, error, stage, partial, recipients, updatedEmailFailedEventData
email.cancelledemailId, from, tagsEmailCancelledEventData
email.scheduledemailId, from, tags, source, recipientsEmailAcceptedEventData
email.queuedemailId, from, tags, source, recipientsEmailAcceptedEventData
email.deliveredemailId, from, tags, recipients, updated, smtpResponseEmailDeliveredEventData
email.delivery_delayedemailId, from, tags, recipients, updated, delayType, expirationTime, diagnosticEmailDeliveryDelayedEventData
email.bouncedemailId, from, tags, recipients, updated, bounceType, bounceSubType, permanent, suppressed, diagnostic, threadId, messageId, fromName, date, subject, to, attachments, spam, muted, encryption, rules, outcome, status, correlatedEmailBouncedEventData, MailboxBounceEventData
email.complainedemailId, from, tags, recipients, updated, complaintFeedbackType, suppressedEmailComplainedEventData
email.suppressedemailId, from, tags, recipients, reasonEmailSuppressedEventData
email.openedemailId, trackedMessageId, threadId, messageId, subject, from, tags, recipient, attributed, first, client, device, os, userAgent, ip, network, country, region, city, timezone, via, openCount, openedAtEmailOpenedData
email.clickedemailId, trackedMessageId, threadId, messageId, subject, from, tags, recipient, attributed, first, client, device, os, userAgent, ip, network, country, region, city, timezone, via, linkId, url, label, clickCount, clickedAtEmailClickedData
email.downloadedemailId, trackedMessageId, threadId, messageId, subject, from, tags, recipient, attributed, first, client, device, os, userAgent, ip, network, country, region, city, timezone, via, shareId, fileId, filename, mimeType, sizeBytes, url, downloadCount, downloadedAtEmailDownloadedData
domain.verifieddomainId, domain, verifiedAt, records, sendingStateDomainVerifiedEventData
domain.sending_changeddomainId, domain, previousState, state, changedAtDomainSendingChangedEventData
domain.deleteddomainId, domain, reason, deletedAtDomainDeletedEventData
suppression.addedemail, reason, detail, addedAt, removedAtSuppressionEventData
suppression.removedemail, reason, detail, addedAt, removedAtSuppressionEventData
file.uploadedfileId, filename, mimeType, sizeBytes, direction, to, threadId, messageId, uploadedAt, deletedAtFileEventData
file.deletedfileId, filename, mimeType, sizeBytes, direction, to, threadId, messageId, uploadedAt, deletedAtFileEventData
form.submittedformId, formName, submissionId, email, status, answers, audienceIds, sourceUrl, submittedAtFormSubmittedEventData
form.confirmedformId, formName, submissionId, email, audienceIds, via, confirmedAtFormConfirmedEventData
automation.enteredautomationId, enrollmentId, contactId, source, enteredAtAutomationEnteredEventData
automation.exitedautomationId, enrollmentId, contactId, reason, stepKey, exitedAtAutomationExitedEventData
automation.pausedautomationId, reason, detailAutomationPausedEventData
automation.resumedautomationId, resumedAtAutomationResumedEventData
automation.webhookautomationId, enrollmentId, stepKey, stepName, contact, dataAutomationWebhookEventData
contact.createdcontactId, email, name, source, createdAt, updatedAt, deletedAtContactEventData
contact.updatedcontactId, email, name, source, createdAt, updatedAt, deletedAtContactEventData
contact.deletedcontactId, email, name, source, createdAt, updatedAt, deletedAtContactEventData
contact.unsubscribedcontactId, email, audienceIds, broadcastId, automationId, unsubscribedAt, resubscribedAtContactSubscriptionEventData
contact.resubscribedcontactId, email, audienceIds, broadcastId, automationId, unsubscribedAt, resubscribedAtContactSubscriptionEventData
sending.pausedstream, reason, recipients, bounced, complained, pausedAtSendingPausedEventData
sending.resumedstream, resumedAtSendingResumedEventData
connector.connectedid, app, appName, scope, access, connectedAt, disconnectedAt, reason, atConnectorEventData
connector.disconnectedid, app, appName, scope, access, connectedAt, disconnectedAt, reason, atConnectorEventData
connector.needs_attentionid, app, appName, scope, access, connectedAt, disconnectedAt, reason, atConnectorEventData
task.run.completedrunId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt, finishedAtTaskRunEventData
task.run.failedrunId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt, finishedAtTaskRunEventData
task.run.cancelledrunId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt, finishedAtTaskRunEventData
approval.requestedapprovalId, runId, taskId, taskName, tool, expiresAt, requestedAtApprovalRequestedEventData
booking.createdbookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, atBookingEventData
booking.confirmedbookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, atBookingEventData
booking.rescheduledbookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, atBookingEventData
booking.cancelledbookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, atBookingEventData
broadcast.sendingbroadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, atBroadcastEventData
broadcast.sentbroadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, atBroadcastEventData
broadcast.failedbroadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, atBroadcastEventData
broadcast.cancelledbroadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, atBroadcastEventData

email.bounced comes in two shapes. A bounce reported for a send of yours names the send by emailId and lists recipients, bounceType and suppressed. A delivery report that arrives at one of your addresses is filed like other mail, so it carries the fields of email.received with outcome, status, correlated and recipients added. Tell them apart by outcome, which only the second has.

Reference