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を返します。 それ以外(リダイレクトやタイムアウトを含む)は再試行されます。リトライをご覧ください。
リクエストの形式
Section titled “リクエストの形式”配信は、すべて Content-Type: application/json の POST で、次のヘッダーが付きます。
| ヘッダー | 値 |
|---|---|
webhook-id |
この配信の一意な id。再試行でも同じ id なので、重複排除に使えます。 |
webhook-timestamp |
この試行を送信した Unix 時間(秒)。 |
webhook-signature |
v1,<base64 HMAC-SHA256>。署名が複数ある場合は、スペース区切りのリストになります。 |
svix-id、svix-timestamp、svix-signature |
上の 3 つのヘッダーと同一内容の複製で、Svix のライブラリがそのまま動作します。 |
ボディは { "type": "...", "created_at": "...", "data": { ... } } です。イベントタイプをご覧ください。
Webhook を管理する
Section titled “Webhook を管理する”POST /webhooks、GET /webhooks、GET /webhooks/{id}、PATCH /webhooks/{id}(endpoint、events、status を変更できます。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 秒以内に応答すること。
- リダイレクトには従いません。
イベントタイプとペイロードすべてのイベントとペイロードの例。
ベストプラクティス冪等で、高速で、安全なハンドラー。