Webhook を受け取る
新しい項目が保存された瞬間に、あなたのエンドポイントへ直接送ります。項目が検索可能になること(またはならなかったこと)と削除されることはポーリングでは分からず、この経路でしか届きません。送信先はアカウント画面で登録します。
ヘッダー
すべての送信に付きます。検証するかどうかは任意です。
| ヘッダー | 例 | 内容 |
|---|---|---|
webhook-id | msg_2KWPBg… | 冪等キー。1 つのイベントの再試行を通じて同一です。 |
webhook-timestamp | 1614265330 | unix 秒。直近の値か確認してリプレイを防ぎます。 |
webhook-signature | v1,g0hM9SsE… | 本文の HMAC-SHA256、base64。 |
content-type | application/json | 常にこの値です。 |
| 登録した認証ヘッダー名 | 登録した認証ヘッダー値 | 登録していれば一緒に送られます。 |
POST <your endpoint>
content-type: application/json
webhook-id: msg_2KWPBgLlAfxdpx2AI54pPJ85f4W
webhook-timestamp: 1614265330
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=
本文
封筒は常に同じで、type が data の形を決めます。
| type | data | タイミング |
|---|---|---|
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": {}
}
単体の保存とアップロード
どちらの流れも同じイベント種別を使います。どちらなのかは status と group_id で分かります。
単体の保存 — MCP・REST・ダッシュボードから保存したとき。note.created が 1 件届いて終わりで、その時点ですでに検索できます。
ファイルのアップロード — ファイルは断片に分かれ、断片ごとに note.created が届きます。その時点ではまだどれも検索できず、準備が終わると note.ready が別に届きます。
| 単体の保存 | アップロード(1 ファイル) | |
|---|---|---|
note.created | 1 件、status: "ready"、group_id: null | 断片ごとに 1 件、status: "pending"、group_id あり |
note.ready | 届きません | 断片が検索可能になったときに届きます |
note.failed | 届きません | 断片を検索可能にできなかったときに届きます |
| 検索できるようになる時点 | note.created | note.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 回処理してしまいます。 |
重複には 200、429 は不可 | 429 は「速度を落とせ」なので再送します。 |
data.id で並べ替える | 再送が後のイベントを追い越します。順序は保証しません。 |
| 最終 URL を登録する | リダイレクトは追わないので 3xx はその場で終了します。 |
署名の検証(任意)
送信元がこちらであること、本文が途中で改変されていないことを確かめる手順です。
- 署名対象の文字列を作る —
{webhook-id}.{webhook-timestamp}.{生の本文} - 鍵を作る — シークレットから
whsec_を取り除き、残りを base64 デコード - HMAC-SHA256 のあと base64 で符号化し、
v1,の後ろの値と比較 webhook-timestampが現在時刻から数分以内か確認- 受け取った生のバイト列で検証する — JSON を解析して再度直列化すると署名が壊れます
- Standard Webhooks のライブラリ(standardwebhooks.com)を使えば 1〜5 を代わりに行います
署名シークレットはアカウント画面にあり、そこでコピーや交換ができます。
再試行
失敗した場合は最大 3 回まで送り直します(初回を含めて全 4 回)。成功とみなすのは 2xx だけです。
| 応答 | こちらの動作 |
|---|---|
2xx | 完了。 |
408・429・5xx | 15 分後、1 時間後、3 時間後に再試行します。 |
| 応答がまったくない | 同じ間隔で再試行します。 |
3xx とその他すべての 4xx | その場で終了します — 答えは変わりません。 |
失敗が続いても送信を自動で止めることはありません。その間は 1 日に最大 1 通メールでお知らせし、アカウント画面に連続失敗回数と最後のエラーが表示されます。
レシーバーが 4 時間以上停止していた場合は GET /api/v1/notes/changes で追いついてください。
さらに
送信先の登録、署名キー、接続テストはすべてアカウント画面にあります。REST API のキー・エンドポイント・エラーは REST API のドキュメントにあります。よくある ご質問は FAQ にまとめてあります。分かりにくいところや不具合があれば お問い合わせください — すべてのメッセージに人が目を通します。