Webhook を受け取る

新しい項目が保存された瞬間に、あなたのエンドポイントへ直接送ります。項目が検索可能になること(またはならなかったこと)と削除されることはポーリングでは分からず、この経路でしか届きません。送信先はアカウント画面で登録します。

ヘッダー

すべての送信に付きます。検証するかどうかは任意です。

ヘッダー内容
webhook-idmsg_2KWPBg…冪等キー。1 つのイベントの再試行を通じて同一です。
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 回ごとに、グループごとに 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
  }
}

アップロードの断片 1 つ

{
  "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" }
    ]
  }
}

1 つのファイルで一部だけ準備が終わり、残りが失敗することがあります。その場合は同じ 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 が 1 件届いて終わりで、その時点ですでに検索できます。

ファイルのアップロード — ファイルは断片に分かれ、断片ごとに 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 はファイルごとに 1 回ではありません — 同時に準備が終わった断片をまとめて送るので、処理が分かれたり、ある断片をやり直したりすると、同じ group_id で複数回届きます。count はそのとき送った件数であって、ファイル全体の断片数ではないので、items を積み上げてください。
  • note.failed は項目が削除されたという意味ではありません — 項目は保存されていて読むこともでき、失敗したのは検索の準備だけです。お手元の控えから削除しないでください。削除には note.deleted という別のイベントがあります。ダッシュボードで再試行を押すと準備をやり直し、それでも失敗すると note.failed が新たに届きます。

レシーバーの作り方

受け取ったらすぐ 2xx を返し、処理は自分のキューで行ってください。

すべきことしないと
すぐ 2xx を返し、処理は後で25 秒を超えると失敗とみなして再送します。
webhook-id で重複を除く同じ項目を 2 回処理してしまいます。
重複には 200429 は不可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完了。
4084295xx15 分後、1 時間後、3 時間後に再試行します。
応答がまったくない同じ間隔で再試行します。
3xx とその他すべての 4xxその場で終了します — 答えは変わりません。

失敗が続いても送信を自動で止めることはありません。その間は 1 日に最大 1 通メールでお知らせし、アカウント画面に連続失敗回数と最後のエラーが表示されます。

レシーバーが 4 時間以上停止していた場合は GET /api/v1/notes/changes で追いついてください。

さらに

送信先の登録、署名キー、接続テストはすべてアカウント画面にあります。REST API のキー・エンドポイント・エラーは REST API のドキュメントにあります。よくある ご質問は FAQ にまとめてあります。分かりにくいところや不具合があれば お問い合わせください — すべてのメッセージに人が目を通します。