핵심 기능기능프라이싱보안문서변경이력
로그인무료로 시작하기

시작하기

  • QA Note란?
  • 빠른 시작 가이드
  • Extension 설치
  • 프로젝트 멤버

기능 가이드

  • 스크린샷 & 어노테이션
  • 세션 레코딩
  • 유지보수 리포트
  • 이슈 상태 모델
  • 멀티 이슈 윈도우
  • Storage · DOM 스냅샷

연동

  • GitHub
  • 커밋 키
  • MCP 서버
  • Slack
  • Webhook
  • Vercel
  • 기존 Playwright

API 레퍼런스

  • 인증
  • 엔드포인트 레퍼런스
  • 공개 API v1
  • 에러 처리

AI 에이전트와 함께 쓰는 이슈 트래커. 수정은 당신의 에이전트가, 기록은 QA Note가.

Made in Seoul · © 2026 QA Note
제품핵심 기능기능프라이싱보안변경이력
리소스문서MCP 가이드Chrome 확장
회사브랜드이용약관개인정보처리방침

에프에프지지(ffgg)|대표: 한송욱

사업자등록번호: 746-54-00870[사업자정보확인]|통신판매업신고번호: 제 2024-서울마포-2178 호

주소: 서울특별시 마포구 월드컵북로6길 26, 5층(동교동, 삼기빌딩)

이메일: support@qanote.app|호스팅 제공자: Vercel Inc.

© 2026 QA Note. All rights reserved.

이용약관개인정보처리방침쿠키정책
  1. 홈
  2. /
  3. Docs
  4. /
  5. 연동

Webhook

이슈 이벤트를 외부 URL 로 전송합니다. Slack · GitHub 외 커스텀 연동에 사용합니다.

목차
  • 사용 사례
  • 설정 방법
  • 이벤트 종류
  • 페이로드 스키마
  • 서명 검증 (HMAC)
  • 재시도 정책
  • 트러블슈팅
  • 받기는 받는데 body 가 비어 있음
  • Signature 검증 실패
  • 재시도가 너무 많음

QA Note 가 기본 제공하는 Slack · GitHub · Vercel 통합 외의 외부 시스템과 연동할 때 사용합니다. 이슈가 생성·수정·코멘트될 때마다 지정한 URL 로 JSON payload 가 전송됩니다. Linear · Jira · 자체 Discord 봇 · Notion DB 등 어디든 받을 수 있는 쪽에서 처리하면 됩니다.

사용 사례

시스템용도
LinearQA Note 이슈를 Linear 이슈로 자동 미러링
Jira우선순위 critical 이슈만 Jira 백로그에 자동 등록
Discord디자이너 채널에 디자인 라벨 이슈만 알림
Notion이슈 메타데이터를 Notion DB 행으로 추가
자체 알림 시스템사내 Slackbot · Teams · 메일 · SMS 게이트웨이

이미 직접 연동(Slack · GitHub) 이 있는 경우 webhook 을 중복으로 켜둘 필요는 없습니다. webhook 은 항상 직접 연동이 커버하지 못하는 경로용 폴백입니다.

설정 방법

대시보드에서 다음 경로로 진입합니다.

프로젝트 설정 → 연동 → Webhook → URL · Secret 입력
경로: /settings/projects/[projectId]/integrations/webhook
입력설명
URLPOST 요청을 받을 외부 엔드포인트 (HTTPS 필수)
SecretHMAC-SHA256 서명 검증용 임의 문자열 (32자 이상 권장)
구독 이벤트issue.* 중 받을 이벤트 선택
활성/비활성임시 중단 토글

URL 은 HTTPS 만 허용됩니다. localhost / 사설 IP 도 거부됩니다 (개발 중에는 cloudflared 등 터널을 통해 공개 URL 로 노출).

이벤트 종류

이벤트발생 조건
issue.created새 이슈가 생성됨 (Extension · 리포터 제보 · 대시보드 어디서든)
issue.updated제목 · 본문 · 우선순위 등이 변경됨
issue.status_changed상태가 변경됨 (open → in_progress 등)
issue.commented이슈에 코멘트가 추가됨
issue.assigned담당자가 변경됨
issue.label_added · issue.label_removed라벨이 추가/제거됨
issue.merged연결된 PR 이 머지됨 (GitHub 통합)
issue.deleted이슈가 삭제됨 (휴지통 행 · 영구 삭제 모두 포함)

여러 이벤트를 동시에 구독할 수 있고, 한 프로젝트에 여러 webhook 을 등록할 수 있습니다 (현재 최대 5 개).

페이로드 스키마

POST body 는 다음 형태의 JSON 입니다.

json
{
  "id": "evt_01H...",
  "type": "issue.created",
  "project": { "id": "proj_xyz", "slug": "acme-app" },
  "issue": {
    "id": "iss_abc",
    "number": 42,
    "title": "로그인 에러",
    "status": "open",
    "priority": "high",
    "url": "https://qanote.app/i/abc-42"
  },
  "actor": { "id": "usr_123", "name": "홍길동", "email": "hong@example.com" },
  "timestamp": "2026-05-01T09:30:12.000Z"
}
필드타입설명
idstring이벤트 ID (재시도 시에도 동일하게 유지 — idempotency key 로 사용 가능)
typestring이벤트 종류 (위 §이벤트 종류 표)
projectobject이슈가 속한 프로젝트
issueobject이슈 핵심 필드 (전체 메타데이터는 url 로 추가 조회)
actorobject | null이벤트를 발생시킨 사용자. 시스템 자동 변경(예: 커밋 키 감지에 의한 수정 제출 전환) 시 null
timestampISO 8601이벤트 발생 시각 (UTC)

이슈의 풍부한 메타데이터(콘솔 로그 · 스크린샷 등)는 webhook payload 에 포함되지 않습니다. 필요한 경우 issue.url 로 이슈를 다시 조회하거나 MCP resolve_by_url 을 사용합니다.

서명 검증 (HMAC)

webhook 요청에는 다음 헤더가 포함됩니다.

헤더값
Content-Typeapplication/json
User-AgentQANote-Webhook/1.0
X-Qanote-Eventissue.created 등 이벤트 종류
X-Qanote-Delivery이벤트 ID (evt_01H...)
X-Qanote-Signaturesha256=<HMAC-SHA256(secret, rawBody)>

받는 쪽은 raw body 와 secret 으로 직접 HMAC 을 계산해 헤더 값과 timing-safe 비교합니다.

ts
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, signatureHeader: string, secret: string): boolean {
  // 헤더 형식: "sha256=<hex>"
  const [scheme, signature] = signatureHeader.split("=");
  if (scheme !== "sha256" || !signature) return false;

  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");

  // 길이가 다르면 즉시 false (timingSafeEqual 은 길이 다르면 throw)
  if (expected.length !== signature.length) return false;

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

JSON.parse 한 결과가 아니라 raw body 문자열 로 HMAC 을 계산해야 합니다. JSON.stringify 로 재직렬화하면 키 순서·공백 차이로 서명이 어긋납니다.

재시도 정책

수신 측이 200~299 가 아닌 응답을 반환하거나 타임아웃(10초) 되면 재시도합니다.

시도대기 시간
1 차즉시
2 차30 초 후
3 차5 분 후
4 차30 분 후
5 차 (최종)4 시간 후

5 차까지 모두 실패하면 이벤트는 폐기되고, 프로젝트 대시보드 → Webhook 설정 → "최근 실패" 목록에 빨간 마커로 누적됩니다. 같은 webhook 이 24 시간 내 50 회 이상 연속 실패하면 자동으로 비활성화되고 알림이 발송됩니다.

재시도 시에도 X-Qanote-Delivery (이벤트 ID) 는 동일하게 유지됩니다. 받는 쪽은 이 값을 idempotency key 로 활용해 중복 처리를 회피하세요.

트러블슈팅

받기는 받는데 body 가 비어 있음

  • Express / Next.js Route Handler 에서 raw body 가 아닌 JSON 파서가 먼저 소비한 경우입니다. 서명 검증을 위해 raw body 를 별도로 보존해야 합니다 (Next.js Route Handler 는 await request.text() 로 한 번만 읽고 재사용).
  • proxy 가 body 를 누락한 경우 — Cloudflare · nginx · API Gateway 의 body 크기 한도 확인 (1MB 권장).

Signature 검증 실패

  • raw body 에서 trailing newline 이 추가/제거된 경우. 받는 즉시 그대로 HMAC 에 넣어야 합니다.
  • secret 이 대시보드에서 회전된 후 옛 값을 그대로 사용 중. 회전 시 24 시간 그레이스 윈도우는 없으므로 즉시 갱신 필요.
  • header 파싱에서 sha256= prefix 를 빠뜨리지 않았는지 확인.

재시도가 너무 많음

  • 수신 측이 5xx 또는 timeout 을 반환하고 있다는 신호입니다. 대시보드 → Webhook 설정 → "최근 실패" 에서 응답 코드와 응답 본문을 확인하세요.
  • 의도적으로 처리를 미루려면 200 을 즉시 반환한 뒤 비동기 처리하세요. 5xx 는 재시도를 유발합니다.
이전
Slack
다음
Vercel

목차

  • 사용 사례
  • 설정 방법
  • 이벤트 종류
  • 페이로드 스키마
  • 서명 검증 (HMAC)
  • 재시도 정책
  • 트러블슈팅
  • 받기는 받는데 body 가 비어 있음
  • Signature 검증 실패
  • 재시도가 너무 많음