Tipos de evento
Assine qualquer combinação destes tipos de evento ao criar um webhook.
| Evento | Dispara quando | Define last_event como |
|---|---|---|
email.scheduled |
Um e-mail com scheduled_at foi aceito. |
scheduled |
email.sent |
O e-mail foi entregue ao Amazon SES. | sent |
email.delivered |
O servidor de e-mail do destinatário aceitou o e-mail. | delivered |
email.delivery_delayed |
A entrega está atrasada ou falhando temporariamente; o SES continua tentando. | delivery_delayed |
email.bounced |
Falha permanente (o endereço não existe, o domínio rejeita). | bounced |
email.complained |
O destinatário marcou o e-mail como spam. | complained |
email.opened |
O destinatário abriu o e-mail (exige o rastreamento de aberturas). | opened |
email.clicked |
O destinatário clicou em um link (exige o rastreamento de cliques). | clicked |
email.failed |
O SpacePost ou o SES não conseguiu enviar o e-mail (rejeitado, falha de renderização, equipe ou tenant pausado). | failed |
email.suppressed |
Um destinatário foi ignorado por estar na sua lista de supressão. | suppressed |
Formato do payload
Seção intitulada “Formato do payload”Os corpos dos webhooks são exatamente os do Resend, então os handlers escritos para o Resend continuam funcionando.
{ "type": "email.delivered", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "broadcast_id": "0192e1c4-0000-7000-8000-0000000000bb", "tenant_id": "0192e1c4-5555-7000-8000-0000000000cc", "tags": { "category": "welcome" } }}typeé o evento;created_até quando o evento aconteceu.data.email_id,from,to(todos os destinatários do e-mail, não apenas o afetado),subjectecreated_at(quando o e-mail foi criado) estão sempre presentes.data.broadcast_idsó está presente em e-mails de campanhas.data.tenant_idsó está presente quando o e-mail foi enviado para um tenant (modo plataforma). É o nosso id do tenant, não o seuexternal_id.data.tagssó está presente se o e-mail tinha tags, como um objeto ({ "name": "value" }).- Alguns eventos acrescentam mais um objeto a
data, com o nome do evento:bounce,click,open,failedousuppressed. Eles estão listados abaixo. Nada mais é adicionado: não há chavesbounceType,delayTypeoureasonno nível superior.
Exemplos
Seção intitulada “Exemplos”email.scheduled
Seção intitulada “email.scheduled”{ "type": "email.scheduled", "created_at": "2026-10-23T14:02:09.700Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Your trial ends tomorrow", "created_at": "2026-10-23T14:02:09.512Z" }}email.sent
Seção intitulada “email.sent”{ "type": "email.sent", "created_at": "2026-10-23T14:02:10.100Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.delivered
Seção intitulada “email.delivered”{ "type": "email.delivered", "created_at": "2026-10-23T14:02:11.350Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.delivery_delayed
Seção intitulada “email.delivery_delayed”Disparado em atrasos de entrega do SES e em rejeições transitórias. Não há campos extras para um atraso simples. Uma rejeição transitória também traz o objeto bounce (veja abaixo, com type: "Transient").
{ "type": "email.delivery_delayed", "created_at": "2026-10-23T14:07:00.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z" }}email.bounced
Seção intitulada “email.bounced”Somente rejeições permanentes chegam a este evento, e elas adicionam o endereço à sua lista de supressão. data.bounce tem type (Permanent), subType e a message do servidor receptor.
{ "type": "email.bounced", "created_at": "2026-10-23T14:02:12.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["nobody@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "bounce": { "type": "Permanent", "subType": "General", "message": "smtp; 550 5.1.1 The email account that you tried to reach does not exist." } }}Os subtipos de rejeição incluem General, NoEmail, Suppressed, OnAccountSuppressionList, MailboxFull, MessageTooLarge, ContentRejected e AttachmentRejected.
email.complained
Seção intitulada “email.complained”Sem campos extras. O endereço é adicionado à sua lista de supressão.
{ "type": "email.complained", "created_at": "2026-10-23T15:30:00.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Our monthly newsletter", "created_at": "2026-10-23T14:02:09.512Z" }}email.opened
Seção intitulada “email.opened”{ "type": "email.opened", "created_at": "2026-10-23T14:05:44.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "open": { "ipAddress": "203.0.113.7", "userAgent": "Mozilla/5.0 (Macintosh)" } }}email.clicked
Seção intitulada “email.clicked”{ "type": "email.clicked", "created_at": "2026-10-23T14:06:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "click": { "link": "https://acme.com/get-started", "ipAddress": "203.0.113.7", "userAgent": "Mozilla/5.0 (Macintosh)", "timestamp": "2026-10-23T14:06:10.000Z" } }}email.failed
Seção intitulada “email.failed”{ "type": "email.failed", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "failed": { "reason": "Attachment https://files.acme.com/report.pdf returned HTTP 404" } }}email.suppressed
Seção intitulada “email.suppressed”suppressed.reason é suppression_list (o destinatário está na sua lista de supressão) ou recipient_domain_does_not_accept_mail (o domínio do destinatário não tem servidor de e-mail).
{ "type": "email.suppressed", "created_at": "2026-10-23T14:02:10.000Z", "data": { "email_id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10", "from": "Acme <hello@acme.com>", "to": ["user@example.com", "other@example.com"], "subject": "Welcome to Acme", "created_at": "2026-10-23T14:02:09.512Z", "suppressed": { "recipients": ["other@example.com"], "reason": "suppression_list" } }}Tipando eventos em TypeScript
Seção intitulada “Tipando eventos em TypeScript”O SDK para Node exporta a união WebhookPayload, discriminada por type, e spacepost.webhooks.verify() a retorna; assim, ao restringir por event.type você obtém os campos corretos de data:
import type { WebhookPayload } from "@spacepost/node";
function handle(event: WebhookPayload) { switch (event.type) { case "email.bounced": return event.data.bounce?.subType; case "email.clicked": return event.data.click?.link; case "email.suppressed": return event.data.suppressed.recipients; case "email.failed": return event.data.failed.reason; default: return event.data.tenant_id; // present when the email was sent for a tenant }}