웹훅 받기

새 항목이 저장되는 순간 회원님이 등록한 주소로 바로 보내 드립니다. 항목이 검색 가능해지는 시점(또는 실패한 시점)과 삭제되는 시점은 폴링으로는 알 수 없어 이 경로로만 옵니다. 받을 주소는 계정 화면에서 등록합니다.

헤더

모든 전송에 붙습니다. 검증은 선택입니다.

헤더예시설명
webhook-idmsg_2KWPBg…멱등 키. 한 이벤트의 재시도 내내 동일합니다.
webhook-timestamp1614265330unix 초. 최근 값인지 확인해 재전송을 막습니다.
webhook-signaturev1,g0hM9SsE…본문의 HMAC-SHA256, base64.
content-typeapplication/json항상 이 값입니다.
등록한 인증 헤더 이름등록한 인증 헤더 값등록했다면 함께 나갑니다.
POST <your endpoint>
content-type: application/json
webhook-id: msg_2KWPBgLlAfxdpx2AI54pPJ85f4W
webhook-timestamp: 1614265330
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=

본문

봉투는 늘 같고, typedata 의 모양을 정합니다.

typedata언제
note.created항목 1건, 본문 포함항목이 저장될 때. 검색 가능하다는 뜻이 아닙니다status 를 보세요.
note.ready{ count, group_id?, items[] }저장된 항목이 검색 가능해질 때. 한 번 처리할 때마다 묶음당 1건입니다.
note.failed{ count, group_id?, items[] }저장된 항목의 검색 준비가 끝내 실패했을 때. 항목은 그대로 남아 있습니다.
note.deleted{ count, items[{id}] }항목이 삭제될 때. id 만 — 이미 사라진 뒤입니다.
webhook.ping{}연결 테스트를 누를 때.

단건 저장

{
  "type": "note.created",
  "timestamp": "2026-09-05T04:12:07Z",
  "data": {
    "id": 41,
    "title": "…",
    "summary": "…",
    "content": "…",
    "created_at": "2026-09-05T04:11:58Z",
    "origin": "Claude",
    "status": "ready",
    "group_id": null
  }
}

업로드 조각 하나

{
  "type": "note.created",
  "timestamp": "2026-09-05T04:12:09Z",
  "data": {
    "id": 42,
    "title": "… (3/77, p.47–53)",
    "summary": "…",
    "content": "…",
    "created_at": "2026-09-05T04:12:08Z",
    "origin": "Upload",
    "status": "pending",
    "group_id": "9f2c1ab84e7d4f0b93c5a61d2e8b7c40"
  }
}

업로드 조각이 검색 가능해졌을 때

{
  "type": "note.ready",
  "timestamp": "2026-09-05T04:31:12Z",
  "data": {
    "count": 2,
    "group_id": "9f2c1ab84e7d4f0b93c5a61d2e8b7c40",
    "items": [
      { "id": 42, "title": "… (3/77, p.47–53)", "status": "ready" },
      { "id": 43, "title": "… (4/77, p.54–60)", "status": "ready" }
    ]
  }
}

업로드 조각의 검색 준비가 실패했을 때

{
  "type": "note.failed",
  "timestamp": "2026-09-05T04:36:40Z",
  "data": {
    "count": 2,
    "group_id": "9f2c1ab84e7d4f0b93c5a61d2e8b7c40",
    "items": [
      { "id": 44, "title": "… (5/77, p.61–67)", "status": "failed" },
      { "id": 45, "title": "… (6/77, p.68–74)", "status": "failed" }
    ]
  }
}

한 파일에서 일부는 준비되고 일부는 실패할 수 있습니다. 그럴 땐 두 이벤트가 같은 group_id 로 몇 초 간격을 두고 옵니다.

항목이 삭제됐을 때

{
  "type": "note.deleted",
  "timestamp": "2026-09-05T05:02:44Z",
  "data": { "count": 2, "items": [{ "id": 42 }, { "id": 43 }] }
}

연결 테스트

{
  "type": "webhook.ping",
  "timestamp": "2026-09-05T05:10:00Z",
  "data": {}
}

단건 저장과 업로드

두 흐름이 같은 이벤트 타입을 씁니다. 어느 쪽인지는 statusgroup_id 로 알 수 있습니다.

단건 저장 — MCP·REST·대시보드에서 저장할 때. note.created 한 건으로 끝나고, 도착한 순간 이미 검색됩니다.

파일 업로드 — 파일이 조각으로 나뉩니다. 조각마다 note.created 가 오지만 아직 검색되지 않고, 준비가 끝나면 note.ready 가 따로 옵니다.

단건 저장업로드 (파일 1개)
note.created1건, status: "ready", group_id: null조각마다 1건, status: "pending", group_id 있음
note.ready오지 않습니다조각이 검색 가능해질 때 옵니다
note.failed오지 않습니다조각을 준비하지 못했을 때 옵니다
검색 가능 시점note.creatednote.ready
조회 가능 시점즉시즉시 — 기다리는 것은 검색뿐입니다
조각 번호필드에 없습니다. 제목의 (3/77)data.id 의 순서뿐입니다
  • status — 검색 가능 여부입니다. "ready" 면 검색되고, "pending" 이면 아직 준비 중이며, "failed" 면 검색 준비가 실패해 검색에서는 찾을 수 없습니다.
  • group_id — 묶음의 이름표입니다. 파일을 올릴 때 발급되고 그 파일의 모든 조각이 같은 값을 갖습니다. 조각의 순번이 아니라 어느 파일에 속하는지를 뜻하고, note.created 와 뒤이어 오는 note.ready 를 잇는 키입니다.
  • 검색되는 것만 필요하다면note.ready 를 신호로 삼고, status"pending"note.created 는 넘기세요.
  • 대기 중인 조각도 바로 읽힙니다 — 본문이 이미 페이로드에 들어 있습니다. 다시 읽어야 하면 열람 수를 올리지 않는 GET /api/v1/notes/{id} 를, 묶음 전체는 GET /api/v1/notes/group/{group_id} 를 쓰세요.
  • note.ready 는 파일당 한 번이 아닙니다 — 한 번에 준비된 조각들을 묶어 보내므로, 처리가 나뉘거나 어떤 조각을 다시 시도하면 같은 group_id 로 여러 번 옵니다. count 는 그때 보낸 개수이지 파일 전체의 조각 수가 아니니 items 를 쌓아 두세요.
  • note.failed 는 항목이 삭제됐다는 뜻이 아닙니다 — 항목은 저장돼 있고 읽을 수도 있으며, 실패한 것은 검색 준비뿐입니다. 보관 중인 사본에서 지우지 마세요. 삭제에는 note.deleted 라는 별도 이벤트가 있습니다. 대시보드에서 다시 시도를 누르면 준비를 다시 하고, 그때도 실패하면 note.failed 가 새로 옵니다.

수신기 만들기

받자마자 2xx 를 돌려주고, 처리는 회원님 쪽 큐에서 하세요.

해야 할 것안 하면
즉시 2xx, 처리는 나중에25초가 넘으면 실패로 보고 다시 보냅니다.
webhook-id 로 중복 제거같은 항목을 두 번 처리하게 됩니다.
중복엔 200, 429 는 금지429 는 “속도를 줄이라”는 뜻이라 저희가 다시 보냅니다.
data.id 로 정렬재시도가 뒤의 이벤트를 앞지릅니다. 순서는 보장하지 않습니다.
최종 URL 을 등록리다이렉트를 따라가지 않아 3xx 는 그 자리에서 끝납니다.

서명 검증 (선택)

저희가 보낸 것이 맞는지, 본문이 도중에 바뀌지 않았는지 확인하는 절차입니다.

  1. 서명 대상 문자열을 만듭니다 — {webhook-id}.{webhook-timestamp}.{원시 본문}
  2. 키를 만듭니다 — 시크릿에서 whsec_ 접두를 떼고 나머지를 base64 디코드
  3. HMAC-SHA256 후 base64 로 인코딩해 v1, 뒤의 값과 비교
  4. webhook-timestamp 가 현재 시각에서 몇 분 이내인지 확인
  5. 받은 원시 바이트로 검증합니다 — JSON 을 파싱했다가 다시 직렬화하면 서명이 깨집니다
  6. Standard Webhooks 라이브러리(standardwebhooks.com)를 쓰면 1~5 를 대신 해 줍니다

서명 키는 계정 화면에 있고 거기서 복사하거나 교체할 수 있습니다.

재시도

실패하면 최대 3번 더 보냅니다(첫 시도 포함 총 4회). 성공으로 치는 것은 2xx 뿐입니다.

응답저희가 하는 일
2xx완료.
408 · 429 · 5xx15분 뒤, 1시간 뒤, 3시간 뒤로 재시도합니다.
응답이 아예 없음같은 간격으로 재시도합니다.
3xx 와 그 밖의 모든 4xx그 자리에서 종료합니다 — 답이 달라지지 않습니다.

실패가 이어져도 발송을 자동으로 끄지는 않습니다. 그동안 하루에 최대 한 번 메일로 알리고, 계정 화면에 연속 실패 횟수와 마지막 오류가 표시됩니다.

수신기가 4시간 넘게 멈춰 있었다면 GET /api/v1/notes/changes 로 따라잡으세요.

더 보기

수신 주소 등록, 서명 키, 연결 테스트는 모두 계정 화면에 있습니다. REST API 의 키·엔드포인트·에러는 REST API 문서에 있습니다. 자주 나오는 질문은 FAQ 에 정리돼 있고, 불분명하거나 잘못된 것이 있으면 문의해 주세요 — 사람이 모든 메일을 읽습니다.