このガイドは、Webhookレシーバーを実装するエンジニア向けです。X-Kanorio-Signature署名の検証方法、べき等性の処理、およびcacheTagsを使用して外部フロントエンドのキャッシュ更新をトリガーする方法に焦点を当てています。
collectionKeysまたはformIdsによるフィルタリングをサポート)、または配信ログの確認については、Webhookの設定と管理を参照してください。dataスキーマ(SSOT): サブスクライブ可能なすべてのイベントコード、必要な権限、およびdataのJSON例は、Webhookリファレンスページのシステムイベントレジストリから自動的に生成されます。すべてのWebhook通知は、HTTPS POSTで送信され、Content-Type: application/jsonおよび以下のヘッダーが含まれます。
| ヘッダー | 説明 |
|---|---|
X-Kanorio-Event | イベントコード(例:collections.item.published、ec.order.paid)。JSONの最上位にある event フィールドと同一です |
X-Kanorio-Delivery | 一意の通知ID。JSONの最上位にある id フィールドと同一です。自動再試行やダッシュボードからの手動「再送信」を行っても変更されません |
X-Kanorio-Signature | HMAC-SHA256署名。形式は t=timestamp,v1=signature です。署名キーの24時間ローテーション期間中は、2つの v1= 値が含まれます |
User-Agent | Kanorio-Notifications/1.0 |
2xxを返す:
2xx応答(例:200 OK、202 Accepted)は、配信成功とみなされます。処理(外部データベースの同期や長時間実行されるタスクのトリガーなど)に時間がかかる場合は、署名の検証とキューイングが完了した直後に200を返し、その後バックグラウンドで非同期に処理してください。3xxリダイレクトに従わない:
KanorioはWebhook送信時に3xxリダイレクトに従いません(301、302、307、または308を受信した場合は配信失敗として扱われます)。ダッシュボードで設定するURLが最終的なエンドポイントであることを確認してください(フレームワークレベルでリダイレクトを引き起こす可能性のある末尾のスラッシュ/に注意してください)。429または5xx応答は、自動的な指数バックオフ再試行をトリガーします。410 Goneはエンドポイントを即座に無効にします。失敗が制限を超えると、システムは自動的にエンドポイントを停止し、チームに通知します。X-Kanorio-Deliveryによるべき等性:
ネットワークの再試行や手動での再配信により、同じ通知が複数回届く可能性があります。X-Kanorio-Delivery(またはトップレベルのJSON id)をべき等性のためのユニークキーとして使用してください。すでに処理済みの場合は、直ちに200 OKを返してください。X-Kanorio-Signature)レシーバーを構築する際は、常にエンドポイントの「署名シークレット」(whsec_...)を使用してX-Kanorio-Signatureを検証し、リクエストがKanorioから送信されたものであり、改ざんされていないことを確認してください。
X-Kanorio-Signatureをカンマ,で分割します。t=の後のUnixタイムスタンプと、v1=の後のすべての16進署名文字列を抽出します(24時間のキーローテーション期間中はv1値が2つ存在します)。tとサーバーの現在時刻を比較します。差が5分(300秒)を超えるリクエストは拒否してください(再試行のたびに、現在時刻を使用してtと署名が再計算されます)。t、ピリオド.、および解析されていない生のリクエストボディを連結して{t}.{rawBody}を作成します。whsec_...シークレットを使用して{t}.{rawBody}のHMAC-SHA256 16進ダイジェストを計算し、crypto.timingSafeEqualを使用して任意のv1と比較します。import { createHmac, timingSafeEqual } from "node:crypto"; export function verifyKanorioWebhook(rawBody, signatureHeader, secret) { if (!signatureHeader || !secret) return false; const parts = signatureHeader.split(",").map((part) => part.split("=")); const t = parts.find(([key]) => key === "t")?.[1]; const signatures = parts .filter(([key]) => key === "v1") .map(([, value]) => value) .filter(Boolean); if (!t || signatures.length === 0) return false; const timestampSec = Number(t); if (!Number.isFinite(timestampSec) || Math.abs(Date.now() / 1000 - timestampSec) > 300) { return false; } const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"); const expectedBuf = Buffer.from(expected, "utf8"); return signatures.some((v1) => { const v1Buf = Buffer.from(v1, "utf8"); return v1Buf.length === expectedBuf.length && timingSafeEqual(expectedBuf, v1Buf); }); }
cacheTagsの更新すべてのWebhookイベントは同じトップレベルのJSON構造を共有し、イベント固有のフィールドはdata内に含まれます。
{ "version": "1", "id": "3f9c2a8b1e4d7c0f9a2b3c4d5e6f7a8b", "event": "collections.item.published", "occurredAt": "2026-10-21T08:30:00.000Z", "websiteId": "cmk1examplewebsiteid", "title": "Collection item published: Sourdough Guide", "summary": "blog/sourdough-guide (published)", "data": { "collectionId": "col_01", "collectionKey": "blog", "itemId": "item_01", "slug": "sourdough-guide", "status": "published", "publicVersion": "1729500000000", "cacheTags": ["site:cmk1examplewebsiteid", "collection:blog", "item:item_01"] }, "actionUrl": "https://app.kanorio.com/data/blog" }
data.cacheTagsによるオンデマンドキャッシュ更新(ISR)すべてのコンテンツおよびコレクション変更イベント(collections.item.*、collections.items.bulkChanged、collections.schema.changed、content.page.*、content.site.published)には、dataオブジェクト内にpublicVersionとcacheTagsが含まれます(Content Delivery API応答のX-Kanorio-Cache-Tagsヘッダーと一致します)。
content.page.updatedにはpreviousSlugが含まれ、cacheTagsにredirectsが追加されます。これにより、外部フロントエンドは古いパスとリダイレクトキャッシュの両方を無効化できます。payload.data.cacheTags内の各タグに対してrevalidateTag(tag)を呼び出すことで、影響を受けるページを数秒以内に正確に更新できます(完全な例についてはを参照してください)。システムイベントレジストリから自動生成されるWebhookリファレンスページをご覧ください。サブスクライブ可能なすべてのイベント、トリガー条件、フィルタサポート、およびdataの例が一覧表示されています。