콘텐츠로 이동

웹훅 개요

웹훅은 이메일 이벤트가 발생하는 즉시 서버로 전달하므로 GET /emails/{id}를 폴링할 필요가 없습니다. SpacePost는 모든 요청에 Standard Webhooks 방식(Svix와 Resend가 쓰는 방식)으로 서명하므로 기존 검증 코드가 그대로 동작합니다.

  1. 엔드포인트를 만듭니다. JSON 본문의 POST를 받고 2xx로 빠르게 응답해야 합니다.

  2. 등록합니다

    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);
    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"
    }
  3. 모든 요청에서 서명을 검증합니다. 서명 검증을 참고하세요.

  4. 2xx를 반환합니다. 그 외의 응답(리디렉션과 시간 초과 포함)은 재시도됩니다. 재시도를 참고하세요.

모든 전달은 Content-Type: application/json과 다음 헤더가 있는 POST입니다.

헤더 값
webhook-id 이 전달의 고유 ID입니다. 재시도해도 같은 ID이므로 중복 제거에 사용하세요.
webhook-timestamp 이 시도를 보낸 시각(Unix 시간, 초 단위)입니다.
webhook-signature v1,<base64 HMAC-SHA256>. 서명이 여러 개이면 공백으로 구분한 목록입니다.
svix-id, svix-timestamp, svix-signature 위 세 헤더와 똑같은 복제본이므로 Svix 라이브러리도 그대로 동작합니다.

본문은 { "type": "...", "created_at": "...", "data": { ... } }입니다. 이벤트 유형을 참고하세요.

POST /webhooks, GET /webhooks, GET /webhooks/{id}, PATCH /webhooks/{id}(endpoint, events, status를 변경할 수 있으며 status는 enabled 또는 disabled), DELETE /webhooks/{id}를 사용합니다. signing_secret은 웹훅을 만들 때와 하나를 조회할 때 반환되며 목록에서는 반환되지 않습니다.

manage-webhooks.ts
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);
  • 프로덕션에서는 https://를 사용해야 합니다(일반 http://는 개발 환경에서만 허용됩니다).
  • 호스트는 공개 주소로 해석되어야 합니다. localhost와 사설 네트워크는 거부됩니다. 로컬 개발에는 ngrok이나 Cloudflare Tunnel 같은 터널을 사용하세요.
  • 15초 안에 응답해야 합니다.
  • 리디렉션은 따라가지 않습니다.