가이드

Webhook

배치 작업 완료 알림 수신

1분 이상 걸리는 배치 작업에서는 Webhook이 폴링보다 저렴하고 빠릅니다. 작업이 종료 상태에 도달하면 Thunderbit가 당신의 URL로 POST합니다.

제출 시 설정

{
  "urls": ["https://example.com/page1"],
  "webhook": {
    "url": "https://your-server.com/api/webhook/distill",
    "secret": "whsec_your_secret_key",
    "headers": { "X-Custom-Auth": "your-token" }
  }
}

webhook.headers 필드는 커스텀 헤더 맵을 받지만, 이 필드는 향후 사용을 위해 예약되어 있으며 현재 서버에서 전송되지 않습니다. 검증은 아래 문서화된 헤더만 기준으로 설계하세요.

요청 헤더

모든 전달에는 다음 4개의 헤더가 포함됩니다:

HeaderValue
Content-Typeapplication/json
X-Webhook-Eventbatch.completed
X-Webhook-TimestampUnix epoch(밀리초)
X-Webhook-Signaturesha256=<base64-encoded HMAC-SHA256>

페이로드

{
  "id": "batch_a1b2c3d4...",
  "jobType": "batch_distill",
  "status": "COMPLETED",
  "total": 50,
  "completed": 49,
  "failed": 1,
  "creditsUsed": 100,
  "createdAt": "2026-04-26T10:00:00Z",
  "completedAt": "2026-04-26T10:05:23Z"
}
  • jobTypebatch_distill 또는 batch_extract.
  • statusCOMPLETED, FAILED, CANCELLED 중 하나.

페이로드는 의도적으로 작게 유지됩니다. 콜백을 받은 후 GET /batch/distill/{id}(또는 /batch/extract/{id})로 전체 결과를 가져오세요.

서명 검증

secret이 설정되면 모든 전달에 X-Webhook-Signature 헤더가 포함됩니다.

  • 알고리즘: HMAC-SHA256
  • 서명 대상 문자열: <X-Webhook-Timestamp>.<raw-json-body>(리터럴 . 사용)
  • 출력 형식: sha256=<base64-encoded-hash>(Base64, hex 아님)

원본 요청 바이트로 검증하세요(JSON을 다시 직렬화하지 마세요). 그 후 상수 시간 비교를 수행합니다.

import hmac, hashlib, base64

def verify(raw_body: bytes, timestamp: str, signature: str, secret: str) -> bool:
    base = f"{timestamp}.{raw_body.decode('utf-8')}".encode('utf-8')
    digest = hmac.new(secret.encode('utf-8'), base, hashlib.sha256).digest()
    expected = "sha256=" + base64.b64encode(digest).decode('ascii')
    return hmac.compare_digest(expected, signature)

재전송 방지

|now - X-Webhook-Timestamp| > 60000(60초 윈도우)이면 요청을 거부하세요. 타임스탬프는 Unix epoch 밀리초 단위입니다. 프로덕션에서는 서명되지 않은 webhook을 절대 신뢰하지 마세요.

재시도 동작

  • 전달당 타임아웃: 30초
  • 최대 재시도: 3회
  • 백오프: 지수 백오프, 시작 1초, 상한 10초
  • 엔드투엔드 총 윈도우: 약 120초

모든 재시도가 실패해도 작업은 우리 쪽에서는 완료된 상태입니다. 수신 엔드포인트는 멱등해야 합니다(id를 중복 제거 키로 사용).