이벤트와 서명
봇에 이벤트가 생기면 봇 관리 > 연동에 저장한 주소로 POST 요청을 보내요. 주소를 저장하고 이벤트를 고르는 방법은 웹훅 설정에 있어요.
이벤트#
| 이벤트 | 보내는 때 |
|---|---|
heart | 누군가 봇에 하트를 눌렀을 때 |
invite.created | 봇에 초대 신청이 들어왔을 때 |
invite.accepted | 제작자가 초대 신청을 수락했을 때 |
test | 연동 화면에서 '테스트 전송'을 눌렀을 때 |
요청 헤더#
| 이름 | 설명 |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | Hankari-Webhook/1.0 (+https://hankari.dev/devs/docs/webhook-events) |
X-Hankari-Event | 이벤트 이름(heart, invite.created, invite.accepted, test) |
X-Hankari-Delivery | 전송마다 다른 id(whd_…). 다시 보낼 때도 같은 값이라 중복을 거를 수 있어요. |
X-Hankari-Signature | sha256={비밀 키로 만든 본문의 HMAC-SHA256, 16진수} |
서명 확인#
웹훅 주소마다 비밀 키가 있어요. 받은 본문을 비밀 키로 HMAC-SHA256 해서 X-Hankari-Signature 값과 비교하면 한카리가 보낸 요청인지 알 수 있어요. 값이 다르면 요청을 버려 주세요.
import crypto from "node:crypto";
// rawBody: 받은 본문 그대로(Buffer). JSON으로 다시 만들면 서명이 달라져요.
export function verifyHankari(rawBody, signature, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature ?? "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}응답과 전송 기록#
2xx로 답하면 받은 것으로 봐요. 그 밖의 응답이나 시간 초과는 실패로 봐요. 결과는 봇 관리 > 연동의 '최근 전송 기록'에 남아요. 5초 안에 답이 없거나 연결이 안 되거나 5xx·429로 답하면 1초 뒤, 그다음 4초 뒤에 다시 보내요(최대 3번). 그 밖의 4xx와 리다이렉트는 다시 보내지 않고 따라가지도 않아요.