메인 콘텐츠로 건너뛰기
웹훅은 주문 처리가 완료되거나 실패할 때 서버에 HTTP POST 콜백을 전달합니다. 주문 조회 엔드포인트를 반복 폴링하는 대신 웹훅을 사용하면 결과가 준비되는 즉시 알림을 받을 수 있습니다.

웹훅 설정

1

웹훅 엔드포인트 등록

API 또는 BIZ MORI 대시보드에서 웹훅 엔드포인트를 생성할 수 있습니다. API를 통해 생성하려면 웹훅 생성 엔드포인트를 사용합니다:
curl -X POST https://api.bizmori.com/api/v2/orders/webhooks \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "내 웹훅",
    "url": "https://your-server.com/webhook"
  }'
응답:
{
  "data": {
    "id": 1,
    "name": "내 웹훅",
    "secret": "whsec_xxxxxxxxxxxxxxxxxx"
  }
}
secret을 즉시 저장하세요 — 한 번만 표시되며 다시 조회할 수 없습니다. 모든 수신 웹훅 서명 검증에 필요합니다.
2

엔드포인트 구현

웹훅 핸들러는 다음을 수행해야 합니다:
  • JSON 본문으로 POST 요청을 수락
  • 5초 이내2xx 상태 코드로 응답
  • 처리 전 X-MoriBiz-Signature 헤더 검증
3

서명 검증

모든 요청에는 X-MoriBiz-Signature 헤더가 포함됩니다. 사용 중인 언어의 구현은 아래 서명 검증을 참고하세요.

이벤트 유형

이벤트 유형설명
order.antiAi.completedAnti-AI 처리 성공 완료
order.antiAi.failedAnti-AI 처리 실패
order.watermarkEmbed.completed워터마크 삽입 성공 완료
order.watermarkEmbed.failed워터마크 삽입 실패
order.watermarkExtract.completed워터마크 추출 성공 완료
order.watermarkExtract.failed워터마크 추출 실패

웹훅 페이로드

모든 웹훅 페이로드는 다음 구조를 따릅니다:
{
  "eventType": "order.antiAi.completed",
  "occurredAt": "2026-02-19T12:00:00.000Z",
  "data": {
    "orderId": "123456789",
    "orderName": "anti_ai_2026-02-19",
    "createdAt": "2026-02-19T11:50:00.000Z",
    "completedAt": "2026-02-19T12:00:00.000Z",
    "status": "complete",
    "fileCount": 3,
    "downloadUrl": "https://s3.amazonaws.com/..."
  }
}

완료 이벤트 데이터

필드타입설명
orderIdstring주문 ID
orderNamestring주문명
createdAtstring주문 생성 시간 (ISO 8601)
completedAtstring처리 완료 시간 (ISO 8601)
statusstringcomplete, detected, 또는 undetected
fileCountinteger처리된 파일 수
downloadUrlstring결과 파일 다운로드 URL (1시간 유효)

실패 이벤트 데이터

필드타입설명
orderIdstring주문 ID
orderNamestring주문명
createdAtstring주문 생성 시간 (ISO 8601)
failedAtstring처리 실패 시간 (ISO 8601)
statusstring항상 failed
error.codestring오류 코드
error.messagestring오류 메시지

워터마크 추출 완료

워터마크 추출 주문의 완료 이벤트에는 추가 필드가 포함됩니다:
필드타입설명
statusstringdetected 또는 undetected
watermarkFoundboolean워터마크 감지 여부
watermarkInfo.textstring감지된 워터마크 텍스트 (watermarkFound가 true일 때만)

서명 검증

X-MoriBiz-Signature 헤더를 확인하여 웹훅 진위를 검증합니다. 이벤트 처리 전에 반드시 검증하세요.
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)          // 원시 요청 바디 문자열 사용
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express 핸들러
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-moribiz-signature'];

  if (!verifyWebhookSignature(req.body.toString(), signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const { eventType, data } = JSON.parse(req.body);
  console.log(`주문 ${data.orderId}${eventType} 이벤트 수신`);
  res.sendStatus(200);
});

재시도 정책

BIZ MORI는 안정적인 웹훅 전송을 보장하기 위해 다단계 재시도 시스템을 사용합니다.

초기 재시도

엔드포인트가 2xx 상태 코드를 반환하지 않으면 BIZ MORI가 즉시 재시도합니다:
시도지연
1차 재시도1초
2차 재시도2초
3차 재시도4초

스케줄러 기반 재시도

초기 재시도가 모두 실패하면, 이벤트는 점차 간격이 늘어나는 스케줄러 기반 재시도 큐에 등록됩니다:
시도지연
4차 재시도30분
5차 재시도2시간
6차 재시도4시간
스케줄러 기반 재시도가 모두 소진되면 이벤트가 FAILED로 표시됩니다. 웹훅 이벤트 목록 엔드포인트를 사용하여 실패한 이벤트를 확인할 수 있습니다.

수동 재전송 API

자동 재시도 프로세스와 관계없이, 재전송 API를 통해 언제든지 수동으로 웹훅을 재전송할 수 있습니다:
# 단일 이벤트 재전송
curl -X POST https://api.bizmori.com/api/v2/orders/webhooks/{webhookId}/events/{eventId}/retry \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# 특정 기간 내 실패한 이벤트 일괄 재전송
curl -X POST https://api.bizmori.com/api/v2/orders/webhooks/{webhookId}/events/retry-failed \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fromDate": "2026-01-01",
    "toDate": "2026-01-07"
  }'

실패 알림 이메일

초기 웹훅 전송이 실패하면 계정 소유자에게 웹훅 전송 실패 알림 이메일을 발송합니다. 과도한 알림을 방지하기 위해 이 이메일은 하루 최대 1회만 발송됩니다.

웹훅 관리

작업엔드포인트
웹훅 목록 조회GET /webhooks
웹훅 생성POST /webhooks
웹훅 상세 조회GET /webhooks/
웹훅 수정PUT /webhooks/
웹훅 삭제DELETE /webhooks/
전송 이벤트 조회GET /webhooks//events
단일 이벤트 재전송POST /webhooks//events//retry
실패 이벤트 일괄 재전송POST /webhooks//events/retry-failed