Visão geral dos webhooks
Os webhooks enviam os eventos de e-mail para o seu servidor assim que acontecem, para que você não precise consultar GET /emails/{id} repetidamente. O SpacePost assina cada requisição com o esquema Standard Webhooks (o mesmo usado pelo Svix e pelo Resend), então o código de verificação que você já tem funciona sem alterações.
-
Crie um endpoint que aceite
POSTcom um corpo JSON e responda2xxrapidamente. -
Registre-o
create-webhook.ts import { SpacePost } from "@spacepost/node";const spacepost = new SpacePost(process.env.SPACEPOST_API_KEY);const { data: webhook, error } = await spacepost.webhooks.create({endpoint: "https://acme.com/webhooks/spacepost",events: ["email.delivered", "email.bounced", "email.complained"],});if (error) throw new Error(`${error.name}: ${error.message}`);// Store this secret: you need it to verify signatures. It starts with "whsec_".console.log(webhook.id, webhook.signing_secret);Janela do terminal curl -X POST https://api.spacepost.dev/webhooks \-H "Authorization: Bearer $SPACEPOST_API_KEY" -H "Content-Type: application/json" \-d '{"endpoint": "https://acme.com/webhooks/spacepost","events": ["email.delivered", "email.bounced", "email.complained"]}'r = requests.post("https://api.spacepost.dev/webhooks",headers={"Authorization": f"Bearer {os.environ['SPACEPOST_API_KEY']}"},json={"endpoint": "https://acme.com/webhooks/spacepost", "events": ["email.delivered", "email.bounced"]},)print(r.json()["signing_secret"])Response {"object": "webhook","id": "0192e1c4-0000-7000-8000-0000000000aa","endpoint": "https://acme.com/webhooks/spacepost","events": ["email.delivered", "email.bounced", "email.complained"],"status": "enabled","created_at": "2026-10-23T14:00:00.000Z","signing_secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"} -
Verifique a assinatura em cada requisição. Veja Verificar assinaturas.
-
Retorne
2xx. Qualquer outra resposta (inclusive redirecionamentos e timeouts) é repetida. Veja Novas tentativas.
Formato da requisição
Seção intitulada “Formato da requisição”Toda entrega é um POST com Content-Type: application/json e estes cabeçalhos:
| Cabeçalho | Valor |
|---|---|
webhook-id |
Id único desta entrega. O mesmo id em cada nova tentativa, então use-o para deduplicar. |
webhook-timestamp |
Horário Unix, em segundos, em que esta tentativa foi enviada. |
webhook-signature |
v1,<HMAC-SHA256 em base64>. Uma lista separada por espaços, se houver várias assinaturas. |
svix-id, svix-timestamp, svix-signature |
Duplicatas idênticas dos três cabeçalhos acima, para que as bibliotecas do Svix funcionem como estão. |
O corpo é { "type": "...", "created_at": "...", "data": { ... } }. Veja Tipos de evento.
Gerenciar webhooks
Seção intitulada “Gerenciar webhooks”POST /webhooks, GET /webhooks, GET /webhooks/{id}, PATCH /webhooks/{id} (altera endpoint, events ou status: enabled ou disabled) e DELETE /webhooks/{id}. O signing_secret é retornado ao criar ou ao buscar um único webhook, não nas listagens.
import { SpacePost } from "@spacepost/node";
const spacepost = new SpacePost(process.env.SPACEPOST_API_KEY);const id = "0192e1c4-0000-7000-8000-0000000000aa";
// Subscribe to more events and temporarily disable delivery.await spacepost.webhooks.update({ id, events: ["email.delivered", "email.bounced", "email.opened"], status: "disabled" });
const { data } = await spacepost.webhooks.list({ limit: 20 });console.log(data?.data.map((w) => `${w.id} ${w.status} ${w.endpoint}`));
await spacepost.webhooks.remove(id);Requisitos dos endpoints
Seção intitulada “Requisitos dos endpoints”https://em produção (http://simples só é aceito em desenvolvimento).- O host deve resolver para um endereço público. Localhost e redes privadas são rejeitados. Para desenvolvimento local, use um túnel como o ngrok ou o Cloudflare Tunnel.
- Responda em até 15 segundos.
- Os redirecionamentos não são seguidos.