가입 즉시 서명 요청 2건 무료. 카드등록 없이 바로 사용가능무료로 시작하기
Webhook / 서명 검증과 재시도

Webhook  /  서명 검증과 재시도

서명 검증과 재시도

서명 검증

받은 요청의 본문 문자열 그대로를 등록할 때 받은 시크릿으로 HMAC-SHA256 계산해 X-PinderSign-Signature 의 sha256= 뒤 값과 비교하세요. 다르면 우리가 보낸 요청이 아닙니다. JSON 을 파싱했다 다시 문자열로 만들면 공백과 키 순서가 달라져 값이 안 맞습니다.

재시도

수신측이 2xx 가 아닌 응답을 주거나 8초 안에 응답하지 않으면 실패로 보고 다시 보냅니다. 최대 6번까지, 간격은 1분 → 5분 → 15분 → 1시간 → 6시간입니다. 재시도 큐는 DB 에 있어서 우리 쪽 재배포로 없어지지 않습니다.

같은 이벤트를 두 번 받을 수 있습니다. 수신측이 200 을 늦게 돌려주면 우리는 실패로 보고 다시 보내기 때문입니다. X-PinderSign-Delivery 값을 저장해 두고 이미 처리한 건이면 건너뛰세요.

전송 이력

GET/webhooks/:id/deliveries
POST/webhooks/:id/deliveries/:deliveryId/retry

최근 50건의 전송 기록을 시도 횟수·마지막 오류와 함께 돌려줍니다. 수신측을 고친 뒤에는 재전송으로 백오프를 기다리지 않고 바로 다시 받을 수 있습니다. 콘솔의 설정 › 개발자에서 같은 목록을 보고 버튼으로 다시 보낼 수도 있습니다.

status뜻
pending아직 성공하지 못했고 재시도가 남음
delivered2xx 를 받음
failed6번 다 실패. 자동 재시도는 끝났고 수동 재전송만 남음

더 궁금한 점이 있나요?

콘솔 사용법은 사용자 가이드를 보세요. 연동 중 막히면 hello@lillo.cx 로 요청·응답을 함께 보내 주세요.

Node.js 검증
javascript
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";

const app = express();

// 본문을 그대로 들고 있어야 한다
app.post("/webhooks/pindersign",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const got = req.header("x-pindersign-signature") ?? "";
    const want = "sha256=" + createHmac("sha256", process.env.HOOK_SECRET)
      .update(req.body)
      .digest("hex");

    const a = Buffer.from(got), b = Buffer.from(want);
    if (a.length !== b.length || !timingSafeEqual(a, b)) {
      return res.sendStatus(401);
    }

    const { event, data } = JSON.parse(req.body);
    // 먼저 200 을 주고 처리는 뒤로 미룬다(8초 제한)
    res.sendStatus(200);
    handle(event, data);
  });
전송 이력
json
[
  {
    "id": "b9d1…",
    "event": "document.completed",
    "status": "failed",
    "attempts": 6,
    "lastError": "status 502",
    "createdAt": "2026-09-19T13:02:14.001Z",
    "deliveredAt": null,
    "nextAttempt": null
  }
]