Webhook 概览
Webhook 会在邮件事件发生时将其推送到你的服务器,因此你无需轮询 GET /emails/{id}。SpacePost 使用 Standard Webhooks 方案(Svix 和 Resend 所用的方案)为每个请求签名,因此现有的验证代码无需修改即可使用。
-
创建一个端点,接受带 JSON 请求体的
POST请求,并快速返回2xx。 -
注册该端点
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);终端窗口 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"} -
验证每个请求的签名。参见验证签名。
-
返回
2xx。 其他任何响应(包括重定向和超时)都会被重试。参见重试。
每次投递都是一个 POST 请求,带有 Content-Type: application/json 以及以下标头:
| 标头 | 值 |
|---|---|
webhook-id |
本次投递的唯一 id。每次重试都使用相同的 id,因此可用它来去重。 |
webhook-timestamp |
本次尝试发送时的 Unix 时间(秒)。 |
webhook-signature |
v1,<base64 HMAC-SHA256>。如果有多个签名,则为以空格分隔的列表。 |
svix-id, svix-timestamp, svix-signature |
与上面三个标头完全相同的副本,因此 Svix 库可直接使用。 |
请求体为 { "type": "...", "created_at": "...", "data": { ... } }。参见事件类型。
管理 Webhook
Section titled “管理 Webhook”POST /webhooks、GET /webhooks、GET /webhooks/{id}、PATCH /webhooks/{id}(可修改 endpoint、events 或 status:enabled 或 disabled)以及 DELETE /webhooks/{id}。signing_secret 会在创建或获取单个 Webhook 时返回,列表中不包含。
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);对端点的要求
Section titled “对端点的要求”- 生产环境使用
https://(纯http://仅在开发环境中被接受)。 - 主机必须解析到公网地址。localhost 和私有网络会被拒绝。本地开发时请使用 ngrok 或 Cloudflare Tunnel 等隧道。
- 请在 15 秒内响应。
- 不会跟随重定向。
事件类型与载荷每种事件及其载荷示例。
最佳实践幂等、快速且安全的处理程序。