Webhook events and stats
The events an endpoint can subscribe to, and how the deliveries went.
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.
{ "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.
{ "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.
{ "id": "evt_4f1c9a2e7b3d4c5e8f9a0b1c", "type": "email.received", "createdAt": "2026-10-14T09:12:40.118Z", "data": { "emailId": "msg_7c2e9a41b3d84f6e9a0c1d2e", "threadId": "thr_2b8e4c1a9d7f4e3b8a6c5d0e", "messageId": "<[email protected]>", "from": "[email protected]", "fromName": "Ada Lovelace", "date": "2026-10-14T09:12:31.000Z", "subject": "The invoice for October", "to": "[email protected]", "attachments": [ { "id": "msg_7c2e9a41b3d84f6e9a0c1d2e-1", "filename": "invoice.pdf", "mimeType": "application/pdf", "size": 48213 } ], "tags": {}, "spam": false, "encryption": null }}| Event | Fields in `data` | SDK type |
|---|---|---|
| email.received | emailId, threadId, messageId, from, fromName, date, subject, to, attachments, tags, spam, muted, encryption, rules | EmailReceivedEventData |
| email.replied | emailId, threadId, messageId, from, fromName, date, subject, to, tags, repliesTo | EmailRepliedEventData |
| email.sent | emailId, from, tags, transport, messageId, threadId, subject, trackedMessageId, source, simulated, test, note | EmailSentEventData |
| email.failed | emailId, from, tags, error, stage, partial, recipients, updated | EmailFailedEventData |
| email.cancelled | emailId, from, tags | EmailCancelledEventData |
| email.scheduled | emailId, from, tags, source, recipients | EmailAcceptedEventData |
| email.queued | emailId, from, tags, source, recipients | EmailAcceptedEventData |
| email.delivered | emailId, from, tags, recipients, updated, smtpResponse | EmailDeliveredEventData |
| email.delivery_delayed | emailId, from, tags, recipients, updated, delayType, expirationTime, diagnostic | EmailDeliveryDelayedEventData |
| email.bounced | emailId, from, tags, recipients, updated, bounceType, bounceSubType, permanent, suppressed, diagnostic, threadId, messageId, fromName, date, subject, to, attachments, spam, muted, encryption, rules, outcome, status, correlated | EmailBouncedEventData, MailboxBounceEventData |
| email.complained | emailId, from, tags, recipients, updated, complaintFeedbackType, suppressed | EmailComplainedEventData |
| email.suppressed | emailId, from, tags, recipients, reason | EmailSuppressedEventData |
| email.opened | emailId, trackedMessageId, threadId, messageId, subject, from, tags, recipient, attributed, first, client, device, os, userAgent, ip, network, country, region, city, timezone, via, openCount, openedAt | EmailOpenedData |
| email.clicked | emailId, trackedMessageId, threadId, messageId, subject, from, tags, recipient, attributed, first, client, device, os, userAgent, ip, network, country, region, city, timezone, via, linkId, url, label, clickCount, clickedAt | EmailClickedData |
| email.downloaded | emailId, 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, downloadedAt | EmailDownloadedData |
| domain.verified | domainId, domain, verifiedAt, records, sendingState | DomainVerifiedEventData |
| domain.sending_changed | domainId, domain, previousState, state, changedAt | DomainSendingChangedEventData |
| domain.deleted | domainId, domain, reason, deletedAt | DomainDeletedEventData |
| suppression.added | email, reason, detail, addedAt, removedAt | SuppressionEventData |
| suppression.removed | email, reason, detail, addedAt, removedAt | SuppressionEventData |
| file.uploaded | fileId, filename, mimeType, sizeBytes, direction, to, threadId, messageId, uploadedAt, deletedAt | FileEventData |
| file.deleted | fileId, filename, mimeType, sizeBytes, direction, to, threadId, messageId, uploadedAt, deletedAt | FileEventData |
| form.submitted | formId, formName, submissionId, email, status, answers, audienceIds, sourceUrl, submittedAt | FormSubmittedEventData |
| form.confirmed | formId, formName, submissionId, email, audienceIds, via, confirmedAt | FormConfirmedEventData |
| automation.entered | automationId, enrollmentId, contactId, source, enteredAt | AutomationEnteredEventData |
| automation.exited | automationId, enrollmentId, contactId, reason, stepKey, exitedAt | AutomationExitedEventData |
| automation.paused | automationId, reason, detail | AutomationPausedEventData |
| automation.resumed | automationId, resumedAt | AutomationResumedEventData |
| automation.webhook | automationId, enrollmentId, stepKey, stepName, contact, data | AutomationWebhookEventData |
| contact.created | contactId, email, name, source, createdAt, updatedAt, deletedAt | ContactEventData |
| contact.updated | contactId, email, name, source, createdAt, updatedAt, deletedAt | ContactEventData |
| contact.deleted | contactId, email, name, source, createdAt, updatedAt, deletedAt | ContactEventData |
| contact.unsubscribed | contactId, email, audienceIds, broadcastId, automationId, unsubscribedAt, resubscribedAt | ContactSubscriptionEventData |
| contact.resubscribed | contactId, email, audienceIds, broadcastId, automationId, unsubscribedAt, resubscribedAt | ContactSubscriptionEventData |
| sending.paused | stream, reason, recipients, bounced, complained, pausedAt | SendingPausedEventData |
| sending.resumed | stream, resumedAt | SendingResumedEventData |
| connector.connected | id, app, appName, scope, access, connectedAt, disconnectedAt, reason, at | ConnectorEventData |
| connector.disconnected | id, app, appName, scope, access, connectedAt, disconnectedAt, reason, at | ConnectorEventData |
| connector.needs_attention | id, app, appName, scope, access, connectedAt, disconnectedAt, reason, at | ConnectorEventData |
| task.run.completed | runId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt, finishedAt | TaskRunEventData |
| task.run.failed | runId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt, finishedAt | TaskRunEventData |
| task.run.cancelled | runId, taskId, taskName, trigger, threadId, status, steps, actions, error, createdAt, finishedAt | TaskRunEventData |
| approval.requested | approvalId, runId, taskId, taskName, tool, expiresAt, requestedAt | ApprovalRequestedEventData |
| booking.created | bookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, at | BookingEventData |
| booking.confirmed | bookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, at | BookingEventData |
| booking.rescheduled | bookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, at | BookingEventData |
| booking.cancelled | bookingId, pageId, status, startAt, endAt, guestName, guestEmail, guestTimezone, location, rescheduleCount, endedBy, reason, createdAt, at | BookingEventData |
| broadcast.sending | broadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, at | BroadcastEventData |
| broadcast.sent | broadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, at | BroadcastEventData |
| broadcast.failed | broadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, at | BroadcastEventData |
| broadcast.cancelled | broadcastId, status, subject, fromEmail, audienceIds, recipients, created, skipped, failed, error, at | BroadcastEventData |
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.