개발자 문서

웹훅

웹훅은 노트가 변경되었다는 사실만 알려주는 서명된 알림입니다. 실제 노트 내용은 REST API로 가져오세요.

웹훅 이벤트

이벤트발생 시점
note.ended녹음 세션이 끝나 최종 전사를 가져올 수 있게 되면 발생합니다. 녹음 세션마다 한 번씩 발생하므로 세션이 여러 개인 노트에서는 여러 번 발생할 수 있습니다.
note.summary.generated요약 생성이 끝나 API로 가져올 수 있게 되면 발생합니다.
note.updated종료된 노트의 제목이나 내용처럼 API를 통해 제공되는 정보가 바뀌면 발생합니다. 짧은 시간에 여러 번 수정하면 알림 하나로 묶어 전송합니다.
note.deleted노트가 삭제되면 이벤트의 data.reason 값은 "deleted"입니다. API 키의 조회 범위를 벗어나면 "access_lost"입니다.

웹훅 엔드포인트 자체와 관련된 이벤트도 두 가지 있습니다. endpoint.verification은 엔드포인트를 만들거나 URL을 바꿀 때 전송됩니다. 이 이벤트에 2xx로 응답하면 엔드포인트가 활성화됩니다. endpoint.test는 콘솔에서 "테스트 전송"을 누르거나 테스트 API를 호출할 때 전송됩니다.

요청 본문 구조

웹훅 요청에는 이벤트 식별자와 처리 상태만 포함되며, 전사나 요약 본문은 포함되지 않습니다. 알림을 받은 뒤 note_id를 사용해 REST API에서 최신 내용을 가져오세요.

JSON
{
  "event_id": "5f8c0a5e-...",
  "event_type": "note.ended",
  "occurred_at": "2026-08-12T05:20:00Z",
  "data": {
    "note_id": "note_abc123",
    "recording_session_id": "rec_456",
    "revision": 7,
    "transcript_status": "ready",
    "summary_status": "pending"
  }
}

서명 검증하기

Alt는 엔드포인트를 만들 때 발급한 whsec_... 시크릿으로 각 요청에 서명합니다. 서명 형식은 Standard Webhooks 규격을 따릅니다:

HTTP
POST /webhooks/alt HTTP/1.1
Content-Type: application/json
webhook-id: 5f8c0a5e-...
webhook-timestamp: 1765515600
webhook-signature: v1,K5oZfzN95Z9UVu1EsPQmSmZQGGVfCM0jaZ0lPI4dvLU=
signature
signed_content = "{webhook-id}.{webhook-timestamp}.{raw request body}"
signature     = base64( HMAC-SHA256( base64url_decode(secret_after_whsec_), signed_content ) )
  • 웹 프레임워크가 JSON을 파싱하기 전의 원본 요청 본문(raw body)으로 서명을 검증하세요. 파싱한 JSON을 다시 직렬화하면 서명이 일치하지 않을 수 있습니다.
  • 타이밍 공격을 방지하려면 서명을 상수 시간 비교 함수로 확인하세요.
  • 재전송 공격을 막으려면 오래된 타임스탬프를 거부하세요. 현재 시각을 기준으로 ±5분 이내만 허용하는 방식을 권장합니다.
  • 서명이 일치하지 않는 요청은 4xx로 거부하세요. 동작하는 수신 서버 코드는 퀵스타트 4단계에 있습니다.

전달 실패와 재시도

  • 웹훅을 받으면 10초 안에 2xx로 응답해야 합니다. 다른 상태 코드나 응답 시간 초과는 전달 실패로 처리됩니다. 먼저 응답한 뒤 실제 작업은 비동기로 처리하세요.
  • 전달에 실패하면 재시도 간격을 점차 늘립니다(30초 → 5분 → 30분 → 2시간 → 12시간 → 12시간, 최대 7회).
  • 연속으로 여러 번 전달에 실패한 엔드포인트는 자동으로 비활성화됩니다.
  • Alt는 리다이렉트를 따라가지 않습니다. 등록한 웹훅 URL이 HTTPS로 직접 응답해야 합니다.

중복 이벤트 처리하기

웹훅은 하나의 이벤트를 한 번 이상 전달할 수 있는 방식(at-least-once)입니다. 재시도하거나 콘솔에서 다시 전송하면 같은 이벤트가 여러 번 도착할 수 있습니다. 처리한 event_id를 일정 기간 저장하고, 이미 처리한 이벤트는 건너뛰세요.

이벤트 순서 처리하기

재시도와 병렬 전송 때문에 이벤트가 발생한 순서와 다르게 도착할 수 있습니다. 가장 나중에 도착한 이벤트가 최신 상태라고 가정하면 안 됩니다. API를 통해 제공되는 노트 정보가 바뀔 때마다 서버가 revision 값을 이전보다 큰 값으로 갱신합니다. 노트마다 마지막으로 반영한 revision을 저장하고, 그 값과 같거나 작은 이벤트는 무시하세요. 판단이 어려우면 REST API로 노트를 다시 가져오세요. API는 항상 현재 revision을 반환합니다.

누락된 변경 사항 확인하기

  • 웹훅 수신 서버가 재시도 기간 안에 복구되지 않거나 엔드포인트가 비활성화되면 일부 알림을 놓칠 수 있습니다. 주기적으로 GET /v1/notes?updated_after=<last sync>를 호출해 마지막 동기화 이후 변경된 노트를 확인하세요.
  • reason: "access_lost"가 포함된 note.deleted는 해당 노트가 API 키의 조회 범위를 벗어났다는 뜻입니다. 예를 들어 개인 노트가 팀스페이스로 이동하면 발생할 수 있습니다. 삭제 이벤트와 같은 방식으로 처리해 저장한 사본을 지우거나 접근을 차단하세요.
  • updated_after를 사용한 증분 조회만으로는 삭제되었거나 조회 범위를 벗어난 노트를 찾을 수 없습니다. 주기적으로 전체 노트 목록도 다시 확인하세요. include_deleted=true를 사용하면 삭제 표시(tombstone)도 함께 받을 수 있습니다. 이전에 저장한 노트 ID가 전체 목록에 없다면 삭제되었거나 조회 범위를 벗어난 것입니다.