웹훅
SubX는 구독 상태가 변경될 때마다 등록된 URL로 이벤트를 전송합니다. HMAC-SHA256 서명으로 페이로드 무결성을 검증할 수 있습니다.
이벤트 타입
| 이벤트 | 설명 |
|---|---|
INITIAL_PURCHASE | 최초 구매 완료 |
RENEWAL | 구독 자동 갱신 성공 |
CANCELLATION | 구독 취소 (다음 갱신일에 만료 예정) |
UNCANCELLATION | 취소 철회 (구독 재활성화) |
BILLING_ISSUE | 결제 실패 (카드 만료, 잔액 부족 등) |
EXPIRATION | 구독 완전 만료 |
PRODUCT_CHANGE | 구독 상품 변경 (업그레이드/다운그레이드) |
REFUND | 환불 처리 완료 |
페이로드 구조
모든 웹훅은 다음 형식의 JSON을 POST로 전송합니다:
webhook-payload.json
{
"id": "evt_abc123",
"type": "INITIAL_PURCHASE",
"timestamp": "2026-02-18T09:30:00Z",
"projectId": "proj_abc123",
"data": {
"customerId": "cust_xyz789",
"appUserId": "user_12345",
"productId": "prod_monthly",
"productIdentifier": "com.example.pro.monthly",
"entitlements": ["pro"],
"store": "APP_STORE",
"currency": "KRW",
"price": 9900,
"transactionId": "txn_abc123",
"purchaseDate": "2026-02-18T09:30:00Z",
"expirationDate": "2026-03-18T09:30:00Z"
}
}전송 헤더
| 헤더 | 설명 |
|---|---|
Content-Type | application/json |
X-SubX-Signature | HMAC-SHA256 서명값 |
X-SubX-Event | 이벤트 타입 (예: INITIAL_PURCHASE) |
서명 검증
웹훅 등록 시 발급되는 Signing Secret을 사용하여 페이로드의 무결성을 검증합니다. 반드시 서명을 검증한 후 이벤트를 처리하세요.
Node.js 예시
import crypto from "crypto";
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express 핸들러 예시
app.post("/webhooks/subx", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-subx-signature"] as string;
const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(payload);
switch (event.type) {
case "INITIAL_PURCHASE":
// 최초 구매 처리
handleInitialPurchase(event.data);
break;
case "RENEWAL":
// 갱신 처리
handleRenewal(event.data);
break;
case "CANCELLATION":
// 취소 처리
handleCancellation(event.data);
break;
// ... 기타 이벤트
}
// 200 응답 (필수)
res.status(200).json({ received: true });
});중요: 중요: 웹훅 핸들러는 반드시 200 상태 코드를 반환해야 합니다. 그렇지 않으면 SubX가 재시도를 수행합니다.
재시도 정책
웹훅 전송에 실패하면(타임아웃 또는 비-2xx 응답) 자동으로 재시도합니다:
| 시도 | 대기 시간 | 누적 시간 |
|---|---|---|
| 1차 재시도 | 1분 후 | +1분 |
| 2차 재시도 | 10분 후 | +11분 |
| 3차 재시도 | 1시간 후 | +1시간 11분 |
3회 재시도 후에도 실패하면 해당 이벤트는 실패 상태로 기록됩니다. 대시보드의 웹훅 로그에서 실패한 이벤트를 확인하고 수동으로 재전송할 수 있습니다.
모범 사례
- 서명 검증 필수: 모든 웹훅에서 X-SubX-Signature 헤더를 검증하세요.
- 멱등성 처리: 동일한 이벤트 ID(evt_...)가 중복 전송될 수 있습니다. 이벤트 ID를 기준으로 중복 처리를 방지하세요.
- 빠른 응답: 웹훅 핸들러는 5초 내에 200 응답을 반환하세요. 오래 걸리는 작업은 큐에 넣고 비동기로 처리하세요.
- HTTPS 필수: 웹훅 URL은 반드시 HTTPS를 사용해야 합니다.
